can1357/oh-my-pi · error
No API key for retry fallback ${selector.raw}
Error message
No API key for retry fallback ${selector.raw} What it means
After successfully resolving the fallback model, TurnRecovery asks the model registry for an API key (getApiKey). If no key is available for that model/provider it throws this error instead of attempting a doomed request. The key may come from the registry's own sources; options.apiKey bypasses the lookup.
Source
Thrown at packages/coding-agent/src/session/turn-recovery.ts:1711
}
}
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_THINKING
? requestedThinkingLevel
: clampThinkingLevelToCeiling(candidate, requestedThinkingLevel, this.#host.thinkingLevelCeiling());
const candidateSelector = formatModelStringWithRouting(candidate);
const previousModel = this.#host.model();
// Mark routing BEFORE the swap: `setModelWithProviderSessionReset` moves the
// model and fans `model_changed` out to subscribers synchronously, and aView on GitHub (pinned to 9690622007)
Solutions
- Pass options.apiKey explicitly when invoking the fallback.
- Configure a key for the fallback provider (env var, provider login, or auth config the registry reads).
- Pick a fallback model whose provider already has a key configured.
- Check getApiKey's key sources (env, config files) for the specific provider and add the missing entry.
Example fix
// before
await recovery.retryWithFallback(selector, { pinFallback: true });
// after
await recovery.retryWithFallback(selector, { pinFallback: true, apiKey: process.env.OPENAI_API_KEY }); Defensive patterns
Strategy: validation
Validate before calling
const key = options.apiKey ?? (await registry.hasApiKey(candidate) ? undefined : await registry.getApiKey(candidate, sessionId));
if (!key && !options.apiKey) throw new Error(`Configure a key for ${candidate.provider} before fallback`);
Try / catch
try {
await recovery.retryWithFallback(selector, opts);
} catch (err) {
if (err instanceof Error && err.message.startsWith("No API key for retry fallback")) {
const provider = selector.raw.split("/")[0];
// prompt user / load from secret store for that provider
} else throw err;
} Prevention
- Configure keys for every provider referenced in any fallback chain.
- Pass options.apiKey explicitly in non-interactive environments (CI).
- Pre-flight check key availability for all configured fallbacks at startup.
- Re-authenticate providers after key rotation.
When it happens
Trigger: Retry-fallback invoked with a valid model but options.apiKey is undefined and the registry cannot find a key for the resolved candidate's provider for this session (no env var, no auth.json/credentials entry, no provider auth configured).
Common situations: Fallback chain crosses to a provider the user never authenticated with (e.g. primary is Anthropic, fallback is OpenAI but OPENAI_API_KEY unset); key was rotated/deleted; running in CI where env secrets are missing.
Understand the failure class
Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.
Related errors
- No API key for ${model.provider}/${model.id}
- No API key available for model ${model.provider}/${model.id}
- Provider ${providerName}: "apiKey" or "oauth" is required wh
- completion() has no API key for ${formatModelString(model)}.
- No API key available for ${model.provider}/${model.id}. Conf
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/5321851298cd1fe0.
Report an issue: GitHub.