@@ -260,10 +260,11 @@ class NativePythonFinderImpl implements NativePythonFinder {
260260 this . restartAttempts = 0 ;
261261 return environment ;
262262 } catch ( ex ) {
263- // On resolve timeout (not configure — configure handles its own timeout),
263+ // On resolve timeout or connection error (not configure — configure handles its own timeout),
264264 // kill the hung process so next request triggers restart
265- if ( ex instanceof RpcTimeoutError && ex . method !== 'configure' ) {
266- this . outputChannel . warn ( '[pet] Resolve request timed out, killing hung process for restart' ) ;
265+ if ( ( ex instanceof RpcTimeoutError && ex . method !== 'configure' ) || ex instanceof rpc . ConnectionError ) {
266+ const reason = ex instanceof rpc . ConnectionError ? 'crashed' : 'timed out' ;
267+ this . outputChannel . warn ( `[pet] Resolve request ${ reason } , killing process for restart` ) ;
267268 this . killProcess ( ) ;
268269 this . processExited = true ;
269270 }
@@ -574,11 +575,14 @@ class NativePythonFinderImpl implements NativePythonFinder {
574575 } catch ( ex ) {
575576 lastError = ex ;
576577
577- // Only retry on timeout errors
578- if ( ex instanceof RpcTimeoutError && ex . method !== 'configure' ) {
578+ // Retry on timeout or connection errors (PET hung or crashed mid-request)
579+ const isRetryable =
580+ ( ex instanceof RpcTimeoutError && ex . method !== 'configure' ) || ex instanceof rpc . ConnectionError ;
581+ if ( isRetryable ) {
579582 if ( attempt < MAX_REFRESH_RETRIES ) {
583+ const reason = ex instanceof rpc . ConnectionError ? 'crashed' : 'timed out' ;
580584 this . outputChannel . warn (
581- `[pet] Refresh timed out (attempt ${ attempt + 1 } /${ MAX_REFRESH_RETRIES + 1 } ), restarting and retrying...` ,
585+ `[pet] Refresh ${ reason } (attempt ${ attempt + 1 } /${ MAX_REFRESH_RETRIES + 1 } ), restarting and retrying...` ,
582586 ) ;
583587 // Kill and restart for retry
584588 this . killProcess ( ) ;
@@ -588,7 +592,7 @@ class NativePythonFinderImpl implements NativePythonFinder {
588592 // Final attempt failed
589593 this . outputChannel . error ( `[pet] Refresh failed after ${ MAX_REFRESH_RETRIES + 1 } attempts` ) ;
590594 }
591- // Non-timeout errors or final timeout - rethrow
595+ // Non-retryable errors or final attempt - rethrow
592596 throw ex ;
593597 }
594598 }
@@ -652,10 +656,11 @@ class NativePythonFinderImpl implements NativePythonFinder {
652656 this . outputChannel . info ( `[pet] Refresh succeeded on retry attempt ${ attempt + 1 } ` ) ;
653657 }
654658 } catch ( ex ) {
655- // On refresh timeout (not configure — configure handles its own timeout),
659+ // On refresh timeout or connection error (not configure — configure handles its own timeout),
656660 // kill the hung process so next request triggers restart
657- if ( ex instanceof RpcTimeoutError && ex . method !== 'configure' ) {
658- this . outputChannel . warn ( '[pet] Request timed out, killing hung process for restart' ) ;
661+ if ( ( ex instanceof RpcTimeoutError && ex . method !== 'configure' ) || ex instanceof rpc . ConnectionError ) {
662+ const reason = ex instanceof rpc . ConnectionError ? 'crashed' : 'timed out' ;
663+ this . outputChannel . warn ( `[pet] PET process ${ reason } , killing for restart` ) ;
659664 this . killProcess ( ) ;
660665 this . processExited = true ;
661666 }
0 commit comments