can1357/oh-my-pi · error · AIError.ConfigurationError
Unhandled API: ${api}
Error message
Unhandled API: ${api} What it means
The API dispatch switch in stream() only knows a fixed set of API kinds. When a model's api field does not match any case, it throws AIError.ConfigurationError with `Unhandled API: ${api}`. This means the model object carries an api value this version of the library cannot stream — usually a mismatch between model metadata and library support.
Source
Thrown at packages/ai/src/stream.ts:1033
case "google-gemini-cli":
return streamGoogleGeminiCli(
providerModel as Model<"google-gemini-cli">,
context,
providerOptions as GoogleGeminiCliOptions,
);
case "ollama-chat":
return streamOllama(providerModel as Model<"ollama-chat">, context, providerOptions as OllamaChatOptions);
case "cursor-agent":
return streamCursor(providerModel as Model<"cursor-agent">, context, providerOptions as CursorOptions);
case "devin-agent":
return streamDevin(providerModel as Model<"devin-agent">, context, providerOptions as DevinOptions);
default:
throw new AIError.ConfigurationError(`Unhandled API: ${api}`);
}
}
/** Maximum guarded attempts for a detected thinking loop. */
const THINKING_LOOP_MAX_ATTEMPTS = 3;
const THINKING_LOOP_RETRY_BASE_DELAY_MS = 500;
const THINKING_LOOP_RETRY_MAX_DELAY_MS = 8_000;
function isRetryableThinkingLoop(message: AssistantMessage): boolean {
return (
message.stopReason === "error" &&
message.content.length === 0 &&
AIError.is(message.errorId, AIError.Flag.ThinkingLoop)
);
}
/**
* Resolve a completion, re-sampling a thinking-loop stall for at mostView on GitHub (pinned to 9690622007)
Solutions
- Upgrade @oh-my-pi/pi-ai (and pi-catalog) so the library recognizes the model's api value.
- Correct the model definition's api field to a supported API kind.
- Remove or replace the stale custom model entry from your registry.
- Check for version mismatches between packages (bun.lock) — reinstall so catalog and ai versions align.
Example fix
// before
const model = { id: "my-model", api: "my-custom-api" /* unknown */ } as Model;
await stream(model, ctx);
// after
const model = { id: "my-model", api: "openai-completions" } as Model<"openai-completions">;
await stream(model, ctx); Defensive patterns
Strategy: try-catch
Validate before calling
const SUPPORTED_APIS = new Set(["openai-completions", "openai-responses", "anthropic-messages", "google-generative-ai", "google-vertex", "bedrock", "gitlab-duo-agent", "cursor-agent", "devin-agent"]);
if (!SUPPORTED_APIS.has(model.api)) {
throw new Error(`Model api "${model.api}" is not supported by this pi-ai version`);
} Type guard
function hasSupportedApi(model: Model): boolean {
return typeof model.api === "string" && streamDispatchSupportsApi(model.api);
} Try / catch
try {
await stream(model, context, requestOptions);
} catch (err) {
if (err instanceof AIError.ConfigurationError && err.message.startsWith("Unhandled API:")) {
console.error(`Library does not support api "${model.api}"; upgrade @oh-my-pi/pi-ai or fix the model entry.`);
return;
}
throw err;
} Prevention
- Keep @oh-my-pi/pi-ai and pi-catalog versions in lockstep.
- Never hand-write model.api strings; build models via the catalog/registry.
- Validate registry entries against supported APIs at startup.
When it happens
Trigger: Streaming a model whose api property is an unrecognized value (custom/older model definition, hand-written model entry, or a model from a newer catalog used with an older @oh-my-pi/pi-ai).
Common situations: Upgraded the model catalog/registry but not the pi-ai package (version skew); constructing a Model object manually with a typo'd api string; custom registry entries copied from another codebase.
Related errors
- Unhandled API in mapOptionsForApi: ${model.api}
- No model configured
- Request was aborted
- Azure OpenAI base URL is required. Set AZURE_OPENAI_BASE_URL
- No response body for V2 compaction streaming
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/041b8ce56fabd10a.
Report an issue: GitHub.