@@ -359,13 +359,100 @@ export class ProviderSettingsManager {
359359 return value
360360 } )
361361
362- // Validate the parsed content against the schema
363- return providerProfilesSchema . parse ( parsedContent )
364- } catch ( error ) {
365- if ( error instanceof ZodError ) {
366- telemetryService . captureSchemaValidationError ( { schemaName : "ProviderProfiles" , error } )
362+ // Validate the parsed content using safeParse to allow for recovery
363+ const validationResult = providerProfilesSchema . safeParse ( parsedContent )
364+
365+ if ( validationResult . success ) {
366+ return validationResult . data
367+ } else {
368+ // Validation failed, attempt recovery if errors are only in apiConfigs
369+ const zodError = validationResult . error
370+ telemetryService . captureSchemaValidationError ( { schemaName : "ProviderProfiles" , error : zodError } )
371+
372+ const nonApiConfigErrors = zodError . issues . filter ( ( issue ) => issue . path [ 0 ] !== "apiConfigs" )
373+
374+ if ( nonApiConfigErrors . length === 0 && parsedContent . apiConfigs ) {
375+ // Errors are only within apiConfigs, attempt filtering
376+ try {
377+ console . warn (
378+ "ProviderSettingsManager: Invalid entries found in apiConfigs during load. Attempting to filter and recover." ,
379+ JSON . stringify (
380+ zodError . issues . filter ( ( issue ) => issue . path [ 0 ] === "apiConfigs" ) ,
381+ null ,
382+ 2 ,
383+ ) ,
384+ )
385+
386+ const filteredApiConfigs : Record < string , ProviderSettingsWithId > = { }
387+ for ( const [ name , config ] of Object . entries ( parsedContent . apiConfigs ) ) {
388+ // Explicitly check if config is a valid object before parsing
389+ if ( typeof config !== "object" || config === null ) {
390+ console . warn (
391+ `ProviderSettingsManager: Skipping invalid profile '${ name } ' during load: Expected object, received ${ typeof config } .` ,
392+ )
393+ continue // Skip this entry entirely
394+ }
395+ // Now safeParse the object
396+ const profileValidation = providerSettingsWithIdSchema . safeParse ( config )
397+ if ( profileValidation . success ) {
398+ filteredApiConfigs [ name ] = profileValidation . data
399+ } else {
400+ console . warn (
401+ `ProviderSettingsManager: Removing invalid profile '${ name } ' during load. Issues:` ,
402+ JSON . stringify ( profileValidation . error . issues , null , 2 ) ,
403+ )
404+ }
405+ }
406+
407+ // Ensure the currentApiConfigName still points to a valid config if possible
408+ let currentApiConfigName = parsedContent . currentApiConfigName
409+ // Check if the original current name exists AND is valid after filtering
410+ if ( ! filteredApiConfigs [ currentApiConfigName ] ) {
411+ const originalName = parsedContent . currentApiConfigName
412+ const availableNames = Object . keys ( filteredApiConfigs )
413+ // Fallback logic: try 'default', then first available, then manager's default
414+ currentApiConfigName = availableNames . includes ( "default" )
415+ ? "default"
416+ : availableNames [ 0 ] || this . defaultProviderProfiles . currentApiConfigName
417+
418+ if ( originalName && originalName !== currentApiConfigName ) {
419+ console . warn (
420+ `ProviderSettingsManager: Current API config '${ originalName } ' was invalid or removed. Switched to '${ currentApiConfigName } '.` ,
421+ )
422+ } else if ( ! originalName ) {
423+ console . warn (
424+ `ProviderSettingsManager: Original currentApiConfigName was missing or invalid. Switched to '${ currentApiConfigName } '.` ,
425+ )
426+ }
427+ // Persisting this change immediately might be better, but requires storing here.
428+ // Let's defer persistence to the next save/store operation for simplicity.
429+ }
430+
431+ // Return a recovered object
432+ return {
433+ currentApiConfigName : currentApiConfigName ,
434+ apiConfigs : filteredApiConfigs ,
435+ modeApiConfigs : parsedContent . modeApiConfigs || this . defaultModeApiConfigs ,
436+ migrations : parsedContent . migrations || this . defaultProviderProfiles . migrations ,
437+ }
438+ } catch ( recoveryError ) {
439+ console . error ( "ProviderSettingsManager: Error occurred during recovery logic:" , recoveryError )
440+ // Re-throw the recovery error to be caught by the outer catch block
441+ throw recoveryError // Ensures it's caught by the final catch
442+ }
443+ } else {
444+ // Errors exist outside apiConfigs or apiConfigs is missing, cannot recover safely
445+ console . error (
446+ "ProviderSettingsManager: Unrecoverable Zod validation failed during load. Issues:" ,
447+ JSON . stringify ( zodError . issues , null , 2 ) ,
448+ )
449+ // Throw a specific error for unrecoverable Zod issues
450+ throw new Error ( `Unrecoverable validation errors in provider profiles structure: ${ zodError } ` )
451+ }
367452 }
368-
453+ } catch ( error ) {
454+ // Catch non-Zod errors or errors during recovery logic
455+ console . error ( "ProviderSettingsManager: Error during load or recovery:" , error )
369456 throw new Error ( `Failed to read provider profiles from secrets: ${ error } ` )
370457 }
371458 }
0 commit comments