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 a

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass options.apiKey explicitly when invoking the fallback.
  2. Configure a key for the fallback provider (env var, provider login, or auth config the registry reads).
  3. Pick a fallback model whose provider already has a key configured.
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/5321851298cd1fe0. Report an issue: GitHub.