@@ -44,10 +44,10 @@ export interface PriorityChainResult {
4444export interface SettingResolutionError {
4545 /** The setting that failed */
4646 setting : 'pythonProjects' | 'defaultEnvManager' | 'defaultInterpreterPath' ;
47+ /** Structured failure kind, used for localization and stale-error re-checks. */
48+ kind : 'managerNotRegistered' | 'pathUnresolvedVariables' | 'pathCannotResolve' ;
4749 /** The configured value */
4850 configuredValue : string ;
49- /** Reason for failure */
50- reason : string ;
5151}
5252
5353/**
@@ -81,8 +81,8 @@ async function resolvePriorityChainCore(
8181 }
8282 const error : SettingResolutionError = {
8383 setting : 'pythonProjects' ,
84+ kind : 'managerNotRegistered' ,
8485 configuredValue : projectManagerId ,
85- reason : `Environment manager '${ projectManagerId } ' is not registered` ,
8686 } ;
8787 errors . push ( error ) ;
8888 traceWarn ( `${ logPrefix } pythonProjects[] manager '${ projectManagerId } ' not found, trying next priority` ) ;
@@ -99,8 +99,8 @@ async function resolvePriorityChainCore(
9999 }
100100 const error : SettingResolutionError = {
101101 setting : 'defaultEnvManager' ,
102+ kind : 'managerNotRegistered' ,
102103 configuredValue : userConfiguredManager ,
103- reason : `Environment manager '${ userConfiguredManager } ' is not registered` ,
104104 } ;
105105 errors . push ( error ) ;
106106 traceWarn ( `${ logPrefix } defaultEnvManager '${ userConfiguredManager } ' not found, trying next priority` ) ;
@@ -118,8 +118,8 @@ async function resolvePriorityChainCore(
118118 ) ;
119119 const error : SettingResolutionError = {
120120 setting : 'defaultInterpreterPath' ,
121+ kind : 'pathUnresolvedVariables' ,
121122 configuredValue : userInterpreterPath ,
122- reason : l10n . t ( 'Path contains unresolved variables' ) ,
123123 } ;
124124 errors . push ( error ) ;
125125 } else {
@@ -138,8 +138,8 @@ async function resolvePriorityChainCore(
138138 ) ;
139139 const error : SettingResolutionError = {
140140 setting : 'defaultInterpreterPath' ,
141+ kind : 'pathUnresolvedVariables' ,
141142 configuredValue : userInterpreterPath ,
142- reason : l10n . t ( 'Path contains unresolved variables' ) ,
143143 } ;
144144 errors . push ( error ) ;
145145 } else {
@@ -155,8 +155,8 @@ async function resolvePriorityChainCore(
155155 }
156156 const error : SettingResolutionError = {
157157 setting : 'defaultInterpreterPath' ,
158+ kind : 'pathCannotResolve' ,
158159 configuredValue : userInterpreterPath ,
159- reason : `Could not resolve interpreter path '${ userInterpreterPath } '` ,
160160 } ;
161161 errors . push ( error ) ;
162162 traceWarn (
@@ -383,8 +383,9 @@ export async function applyInitialEnvironmentSelection(
383383 }
384384 resolveGlobalScope ( )
385385 . then ( async ( globalErrors ) => {
386- if ( globalErrors . length > 0 ) {
387- await notifyUserOfSettingErrors ( globalErrors ) ;
386+ const liveGlobalErrors = filterLiveSettingErrors ( globalErrors , envManagers ) ;
387+ if ( liveGlobalErrors . length > 0 ) {
388+ await notifyUserOfSettingErrors ( liveGlobalErrors ) ;
388389 }
389390 } )
390391 . catch ( ( err ) => traceError ( `[interpreterSelection] Background global scope resolution failed: ${ err } ` ) ) ;
@@ -397,9 +398,11 @@ export async function applyInitialEnvironmentSelection(
397398 allErrors . push ( ...globalErrors ) ;
398399 }
399400
400- // Notify user if any settings could not be applied (workspace + global when awaited)
401- if ( allErrors . length > 0 ) {
402- await notifyUserOfSettingErrors ( allErrors ) ;
401+ // Drop errors that became stale during the awaits above; see filterLiveSettingErrors.
402+ const liveErrors = filterLiveSettingErrors ( allErrors , envManagers ) ;
403+
404+ if ( liveErrors . length > 0 ) {
405+ await notifyUserOfSettingErrors ( liveErrors ) ;
403406 }
404407
405408 // Numeric values must go via the measures argument (properties are dropped).
@@ -409,7 +412,7 @@ export async function applyInitialEnvironmentSelection(
409412 duration : selectionStopWatch . elapsedTime ,
410413 workspaceFolderCount : folders . length ,
411414 resolvedFolderCount,
412- settingErrorCount : allErrors . length ,
415+ settingErrorCount : liveErrors . length ,
413416 } ,
414417 {
415418 globalScopeDeferred : workspaceFolderResolved ,
@@ -430,7 +433,42 @@ export function resetSettingWarnings(): void {
430433 warnedSettings . clear ( ) ;
431434}
432435
436+ function localizedReasonFor ( error : SettingResolutionError ) : string {
437+ switch ( error . kind ) {
438+ case 'managerNotRegistered' :
439+ return l10n . t ( "Environment manager '{0}' is not registered" , error . configuredValue ) ;
440+ case 'pathUnresolvedVariables' :
441+ return l10n . t ( 'Path contains unresolved variables' ) ;
442+ case 'pathCannotResolve' :
443+ return l10n . t ( "Could not resolve interpreter path '{0}'" , error . configuredValue ) ;
444+ }
445+ }
446+
447+ /**
448+ * Re-check the live registry to drop `managerNotRegistered` errors that became
449+ * stale while later awaits ran — a third-party manager extension may have
450+ * registered in the meantime, in which case the warning would be a false positive.
451+ */
452+ function filterLiveSettingErrors (
453+ errors : SettingResolutionError [ ] ,
454+ envManagers : EnvironmentManagers ,
455+ ) : SettingResolutionError [ ] {
456+ return errors . filter ( ( e ) => {
457+ if ( e . kind === 'managerNotRegistered' && envManagers . getEnvironmentManager ( e . configuredValue ) ) {
458+ traceVerbose (
459+ `[interpreterSelection] Manager '${ e . configuredValue } ' is now registered; suppressing stale warning` ,
460+ ) ;
461+ return false ;
462+ }
463+ return true ;
464+ } ) ;
465+ }
466+
433467async function notifyUserOfSettingErrors ( errors : SettingResolutionError [ ] ) : Promise < void > {
468+ if ( errors . length === 0 ) {
469+ return ;
470+ }
471+
434472 // Group errors by setting type to avoid spamming the user
435473 const uniqueSettings = [ ...new Set ( errors . map ( ( e ) => e . setting ) ) ] ;
436474
@@ -442,6 +480,7 @@ async function notifyUserOfSettingErrors(errors: SettingResolutionError[]): Prom
442480
443481 const settingErrors = errors . filter ( ( e ) => e . setting === setting ) ;
444482 const firstError = settingErrors [ 0 ] ;
483+ const reason = localizedReasonFor ( firstError ) ;
445484
446485 let message : string ;
447486 let settingKey : string ;
@@ -451,23 +490,23 @@ async function notifyUserOfSettingErrors(errors: SettingResolutionError[]): Prom
451490 message = l10n . t (
452491 "Python project setting for environment manager '{0}' could not be applied: {1}" ,
453492 firstError . configuredValue ,
454- firstError . reason ,
493+ reason ,
455494 ) ;
456495 settingKey = 'python-envs.pythonProjects' ;
457496 break ;
458497 case 'defaultEnvManager' :
459498 message = l10n . t (
460499 "Default environment manager '{0}' could not be applied: {1}" ,
461500 firstError . configuredValue ,
462- firstError . reason ,
501+ reason ,
463502 ) ;
464503 settingKey = 'python-envs.defaultEnvManager' ;
465504 break ;
466505 case 'defaultInterpreterPath' :
467506 message = l10n . t (
468507 "Default interpreter path '{0}' could not be resolved: {1}" ,
469508 firstError . configuredValue ,
470- firstError . reason ,
509+ reason ,
471510 ) ;
472511 settingKey = 'python.defaultInterpreterPath' ;
473512 break ;
0 commit comments