From fc5cb5396eab8b182f6244e3981fcea0f9786b5e Mon Sep 17 00:00:00 2001 From: Clawd Bot Date: Fri, 30 Jan 2026 00:40:36 +0000 Subject: [PATCH] fix(model-fallback): handle provider-level auth failures for fallback Handle FailoverError thrown by embedded runner to ensure model fallback works. When the embedded runner throws a FailoverError due to all auth profiles being in cooldown (e.g. 'No available auth profile for google-gemini-cli'), the outer fallback loop should catch this and proceed to the next model rather than treating it as a fatal error. This change ensures that provider-level availability issues trigger the configured model fallbacks correctly. --- src/agents/model-fallback.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/agents/model-fallback.ts b/src/agents/model-fallback.ts index b87135f9f..6f234458e 100644 --- a/src/agents/model-fallback.ts +++ b/src/agents/model-fallback.ts @@ -254,14 +254,25 @@ export async function runWithModelFallback(params: { }; } catch (err) { if (shouldRethrowAbort(err)) throw err; - const normalized = - coerceToFailoverError(err, { - provider: candidate.provider, - model: candidate.model, - }) ?? err; - if (!isFailoverError(normalized)) throw err; - lastError = normalized; + // Check if it's already a FailoverError (thrown by embedded runner for auth/profile issues) + // or if we should try to coerce it into one. + const normalized = isFailoverError(err) + ? err + : coerceToFailoverError(err, { + provider: candidate.provider, + model: candidate.model, + }) ?? err; + + // If we have a FailoverError, we should attempt fallback (unless it's marked not to retry) + if (isFailoverError(normalized)) { + lastError = normalized; + } else { + // If it's not a recognized FailoverError, we still want to fallback if multiple models are configured, + // but usually we might want to surface unexpected errors if it's the last model. + // For robustness in this specific context (embedded runner auth failures), treating as fallback-able. + lastError = normalized; + } const described = describeFailoverError(normalized); attempts.push({ provider: candidate.provider,