can1357/oh-my-pi · error · AIError.ConfigurationError
Cannot register custom API "${api}": built-in API names are
Error message
Cannot register custom API "${api}": built-in API names are reserved. What it means
registerCustomApi lets applications plug in custom streaming APIs, but built-in API names (the KnownApi set in BUILTIN_APIS) are reserved so routing and model dispatch stay unambiguous. assertCustomApiName checks the name against that set and throws ConfigurationError if it collides.
Source
Thrown at packages/ai/src/api-registry.ts:65
options?: StreamOptions,
) => AssistantMessageEventStream;
export type CustomStreamSimpleFn = (
model: Model<Api>,
context: Context,
options?: SimpleStreamOptions,
) => AssistantMessageEventStream;
export interface RegisteredCustomApi {
stream: CustomStreamFn;
streamSimple: CustomStreamSimpleFn;
sourceId?: string;
}
const customApiRegistry = new Map<string, RegisteredCustomApi>();
function assertCustomApiName(api: string): void {
if (BUILTIN_APIS.has(api as KnownApi)) {
throw new AIError.ConfigurationError(`Cannot register custom API "${api}": built-in API names are reserved.`);
}
}
/**
* Register a custom API streaming function.
*/
export function registerCustomApi(
api: string,
streamSimple: CustomStreamSimpleFn,
sourceId?: string,
stream?: CustomStreamFn,
): void {
assertCustomApiName(api);
customApiRegistry.set(api, {
stream: stream ?? ((model, context, options) => streamSimple(model, context, options as SimpleStreamOptions)),
streamSimple,
sourceId,
});View on GitHub (pinned to 9690622007)
Solutions
- Choose a distinct namespaced custom API name, e.g. "mycompany-anthropic-proxy"
- If the goal is to change built-in behavior, use the model's api field to point at your custom API name instead of re-registering the built-in name
- Print or log BUILTIN_APIS / the KnownApi union to pick a non-colliding name
Example fix
// before
registerCustomApi("anthropic-messages", myHandler) // reserved
// after
registerCustomApi("acme-anthropic-messages", myHandler)
// then set model.api = "acme-anthropic-messages" Defensive patterns
Strategy: validation
Validate before calling
import { BUILTIN_APIS } from "@oh-my-pi/pi-ai"; // or the registry module exporting the set
if (BUILTIN_APIS.has(myApiName)) {
throw new Error(`API name "${myApiName}" is reserved; pick a namespaced custom name`);
}
registerCustomApi(myApiName, handler); Try / catch
try {
registerCustomApi(name, handler);
} catch (err) {
if (err instanceof AIError.ConfigurationError && err.message.includes("reserved")) {
registerCustomApi(`custom-${name}`, handler);
} else throw err;
} Prevention
- Namespace custom API names with a company/project prefix
- Never name custom APIs after built-in providers
- Point models at custom behavior via the model's api field, not by overriding built-ins
- Keep a central constant list of your app's custom API names
When it happens
Trigger: Calling registerCustomApi with a name equal to a built-in API identifier (e.g. "anthropic-messages", "openai-completions", "openai-responses" or any other entry of BUILTIN_APIS).
Common situations: Trying to override/patch a built-in provider's behavior via the custom registry; copy-pasting a model's api field as the custom name; typos like "openai-chat" that collide with an actual built-in id.
Related errors
- nameError (dynamic message from validateServerName, e.g. "Se
- Invalid OMP profile "${profile}". Profile names must match $
- No model configured
- Azure OpenAI base URL is required. Set AZURE_OPENAI_BASE_URL
- Unable to read OMP_AUTH_BROKER_ACCOUNT_POOL_FILE at ${filePa
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/203f96a516ac902f.
Report an issue: GitHub.