can1357/oh-my-pi · error
Retry fallback model not found: ${selector.raw}
Error message
Retry fallback model not found: ${selector.raw} What it means
TurnRecovery's retry-fallback path resolves a model selector string (e.g. 'provider/model-id') via resolveModelOverride and the model registry, then throws if neither produces a candidate model. This means the selector the caller asked to fall back to does not match any model known to the registry (including any override/pinning logic). It is thrown before any API call is attempted.
Source
Thrown at packages/coding-agent/src/session/turn-recovery.ts:1705
const onAbort = () => aborted.resolve(false);
signal.addEventListener("abort", onAbort, { once: true });
try {
return await Promise.race([confirmer(confirmation, signal), aborted.promise]);
} finally {
signal.removeEventListener("abort", onAbort);
}
}
async applyRetryFallbackCandidate(
role: string,
selector: RetryFallbackSelector,
currentSelector: string,
options?: { pinFallback?: boolean; apiKey?: string; signal?: AbortSignal },
): Promise<boolean> {
const resolved = resolveModelOverride([selector.raw], this.#host.modelRegistry, this.#host.settings);
const candidate = resolved.model ?? this.#host.modelRegistry.find(selector.provider, selector.id);
if (!candidate) {
throw new Error(`Retry fallback model not found: ${selector.raw}`);
}
const apiKey =
options?.apiKey ??
(await this.#host.modelRegistry.getApiKey(candidate, this.#host.sessionId(), { signal: options?.signal }));
if (!apiKey) {
throw new Error(`No API key for retry fallback ${selector.raw}`);
}
if (options?.signal?.aborted) return false;
// Capture the configured selector (auto-aware) so a fallback chain preserves
// `auto` instead of collapsing it to the level it resolved to this turn.
const currentThinkingLevel = this.#host.configuredThinkingLevel();
const requestedThinkingLevel = selector.thinkingLevel ?? currentThinkingLevel;
// A fallback selector's explicit level (or the carried level after the
// replacement model's floor clamp) must never exceed the session's
// per-spawn effort ceiling.
const nextThinkingLevel =
requestedThinkingLevel === AUTO_THINKINGView on GitHub (pinned to 9690622007)
Solutions
- Verify the selector string matches an available model (run the same resolveModelOverride/registry lookup interactively or list registry models).
- Correct the fallback selector in the session/config that supplied it (typos, old ids).
- Ensure the provider's models are registered/loaded before the retry path runs (check registry.getAvailable()).
- If resolveModelOverride returns nothing because the override points at a removed model, clear the stale override.
Example fix
// before
await recovery.retryWithFallback({ raw: "anthropic/claude-3-5-sonet" });
// after
await recovery.retryWithFallback({ raw: "anthropic/claude-3-5-sonnet" }); // id that exists in the registry Defensive patterns
Strategy: validation
Validate before calling
const resolved = resolveModelOverride([selector.raw], registry, settings);
const candidate = resolved.model ?? registry.find(selector.provider, selector.id);
if (!candidate) throw new Error(`Fallback model unavailable: ${selector.raw}`);
Type guard
function isKnownModel(registry: ModelRegistry, provider: string, id: string): boolean {
return registry.find(provider, id) !== undefined;
} Try / catch
try {
await recovery.retryWithFallback(selector, opts);
} catch (err) {
if (err instanceof Error && err.message.startsWith("Retry fallback model not found")) {
// fall back to the primary model or surface a config error to the user
} else throw err;
} Prevention
- Validate model selectors against the registry at config-load time.
- Use autocomplete/managed pickers instead of hand-typed model ids.
- Keep the model catalog updated so renamed ids still resolve.
- Log the list of available models when resolution fails to speed diagnosis.
When it happens
Trigger: Calling the TurnRecovery retry-fallback method with options.pinFallback or a selector whose raw string does not resolve: misspelled model id, model removed/renamed in the registry, or a provider whose models were not loaded/available.
Common situations: A saved session or config references a model id from an older version of the catalog; user hand-edits a fallback selector; provider plugin not registered so its models are absent from the registry; typo in provider name.
Related errors
- Provider ${providerName}: "api" is required when registering
- Provider ${providerName}, model ${modelDef.id}: no "api" spe
- Security scan model is unavailable: ${plan.model.provider}/$
- No model configured
- Azure OpenAI base URL is required. Set AZURE_OPENAI_BASE_URL
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/199cb48ba0994c0f.
Report an issue: GitHub.