{"record":{"id":"ebe59e8247752219","repo":"can1357/oh-my-pi","slug":"provider-providername-model-modeldef-id-no-ebe59e","errorCode":null,"errorMessage":"Provider ${providerName}, model ${modelDef.id}: no \"api\" specified. / Provider ${providerName}, model ${modelDef.id}: no \"api\" specified. Set at provider or model level.","messagePattern":"Provider (.+?), model (.+?): no \"api\" specified\\. / Provider (.+?), model (.+?): no \"api\" specified\\. Set at provider or model level\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/config/models-config.ts","lineNumber":87,"sourceCode":"\t\t\tmode === \"runtime-register\"\n\t\t\t\t? !config.apiKey && !config.oauthConfigured\n\t\t\t\t: !config.apiKey && (config.auth ?? \"apiKey\") !== \"none\" && (config.auth ?? \"apiKey\") !== \"oauth\";\n\t\tif (requiresAuth) {\n\t\t\tthrow new Error(\n\t\t\t\tmode === \"runtime-register\"\n\t\t\t\t\t? `Provider ${providerName}: \"apiKey\" or \"oauth\" is required when defining models.`\n\t\t\t\t\t: `Provider ${providerName}: \"apiKey\" is required when defining custom models unless auth is \"none\" or \"oauth\".`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (mode === \"models-config\" && config.discovery && !config.api && config.discovery.type !== \"proxy\") {\n\t\tthrow new Error(`Provider ${providerName}: \"api\" is required when discovery is enabled at provider level.`);\n\t}\n\n\tfor (const modelDef of models) {\n\t\tif (!hasProviderApi && !modelDef.api) {\n\t\t\tthrow new Error(\n\t\t\t\tmode === \"runtime-register\"\n\t\t\t\t\t? `Provider ${providerName}, model ${modelDef.id}: no \"api\" specified.`\n\t\t\t\t\t: `Provider ${providerName}, model ${modelDef.id}: no \"api\" specified. Set at provider or model level.`,\n\t\t\t);\n\t\t}\n\t\tif (!modelDef.id) {\n\t\t\tthrow new Error(`Provider ${providerName}: model missing \"id\"`);\n\t\t}\n\t\tif (mode === \"models-config\") {\n\t\t\tif (modelDef.contextWindow !== undefined && modelDef.contextWindow <= 0) {\n\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);\n\t\t\t}\n\t\t\tif (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0) {\n\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);\n\t\t\t}\n\t\t}\n\t}\n}","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/config/models-config.ts#L69-L105","documentation":"Thrown by validateProviderConfiguration when a model definition has no \"api\" field and the provider itself does not declare one. The \"api\" field selects which wire protocol (e.g. openai-completions, anthropic-messages) the client uses to talk to the model, so without it the provider cannot be built. The message differs by mode: runtime-register gets the short form, models-config parsing gets a hint that api can be set at provider or model level. A provider-level discovery of type \"proxy\" is also exempt.","triggerScenarios":"Calling registerProvider (runtime) with models lacking api and no provider-level api; or loading a models-config file whose provider entry omits api on both provider and each model while discovery is absent or non-proxy.","commonSituations":"Hand-written custom provider entries copied from docs that assume a provider-level api; provider configs migrated from older versions where api defaulted; JSON/YAML models-config with models listed but api only implied.","solutions":["Set \"api\" on the provider config so all its models inherit it","Or set \"api\" on each model definition that lacks it","If using provider-level discovery, either specify api or set discovery.type to \"proxy\"","Check the model catalog for the correct api value for your endpoint type"],"exampleFix":"// before\n{ \"providers\": { \"my-llm\": { \"baseUrl\": \"http://localhost:8080\", \"models\": [{ \"id\": \"m1\" }] } } }\n// after\n{ \"providers\": { \"my-llm\": { \"baseUrl\": \"http://localhost:8080\", \"api\": \"openai-completions\", \"models\": [{ \"id\": \"m1\" }] } } }","handlingStrategy":"validation","validationCode":"function assertProviderApi(cfg) {\n  if (!cfg.api && !(cfg.models ?? []).every(m => m.api))\n    throw new Error(`Provider ${cfg.name}: set \"api\" at provider or model level`);\n}","typeGuard":"function hasApi(cfg) { return typeof cfg.api === 'string' && cfg.api.length > 0; }","tryCatchPattern":"try { registerProvider(cfg); } catch (e) { if (String(e).includes('no \"api\" specified')) { logger.error('Add api to provider or model config', { provider: cfg.name }); } else throw e; }","preventionTips":["Always set api at the provider level when defining multiple models","Copy provider templates that include api from the docs","Run config validation before deployment"],"tags":["config","provider","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}