← Back to PRs

#21152: fix(agents): throw FailoverError for unknown model so fallback chain is not bypassed

by Mellowambience open 2026-02-19 18:29 View on GitHub →
agents size: XS
## Summary Fixes #21107. When `resolveModel()` cannot find a model in the catalog, it returns `{ error: string }`. The caller in `runEmbeddedPiAgent()` then does: ```ts if (!model) { throw new Error(error ?? `Unknown model: ${provider}/${modelId}`); } ``` Because this is a plain `Error`, `coerceToFailoverError()` in `runWithModelFallback()` does not recognise the message pattern (it checks for rate-limit, billing, auth, timeout, and format strings — not "Unknown model:"). So the error is rethrown immediately, bypassing every fallback candidate the user configured. ## Fix Change the single `throw` to use `FailoverError` (already imported on line 20): ```ts if (!model) { throw new FailoverError( error ?? `Unknown model: ${provider}/${modelId}`, { reason: "format", provider, model: modelId }, ); } ``` `FailoverError` is already caught correctly by `runWithModelFallback()` — the fallback chain will now cascade through all configured fallback models as the user expects. ## Why `reason: "format"` The model-not-found error is structurally analogous to an unsupported-model response (wrong model name / ID doesn't exist). Using `"format"` matches the existing convention used for similar pre-flight errors (see L301-L304 in this file). ## Test cases covered by existing tests - Unknown primary model with valid fallbacks → fallback chain now triggered (was: crash) - Unknown primary model with no fallbacks → plain error still surfaced (FailoverError is rethrown by `runWithModelFallback()` when no more candidates) - Valid model → no behaviour change ## One-line diff ```diff - throw new Error(error ?? `Unknown model: ${provider}/${modelId}`); + throw new FailoverError( + error ?? `Unknown model: ${provider}/${modelId}`, + { reason: "format", provider, model: modelId }, + ); ``` <!-- greptile_comment --> <h3>Greptile Summary</h3> Changed error handling for unknown models from plain `Error` to `FailoverError` with `reason: "format"`, enabling the fallback chain to engage when `resolveModel()` cannot find a model in the catalog. ### Changes - Modified `src/agents/pi-embedded-runner/run.ts:277-280` to throw `FailoverError` instead of plain `Error` when model resolution fails - Added `reason: "format"` metadata to classify the error for fallback handling ### Why this matters Previously, when a model was not found in the catalog, the plain `Error` would bypass `runWithModelFallback()`'s fallback chain because `coerceToFailoverError()` couldn't recognize the "Unknown model:" pattern. Now the fallback chain will correctly cascade through configured fallback models. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk - The change is a focused, single-line fix that correctly uses an existing error class (`FailoverError`) that's already imported and used elsewhere in the file. The `reason: "format"` choice is consistent with the context window guard error on line 304-307 and matches the semantic intent of "unsupported model format". The fallback mechanism in `model-fallback.ts:370-377` correctly handles `FailoverError` instances. - No files require special attention <sub>Last reviewed commit: eea608d</sub> <!-- greptile_other_comments_section --> <sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub> <!-- /greptile_comment -->

Most Similar PRs