{"record":{"id":"ad9a64a90889b9da","repo":"can1357/oh-my-pi","slug":"provider-providername-apikey-or-oauth-is-r","errorCode":null,"errorMessage":"Provider ${providerName}: \"apiKey\" or \"oauth\" is required when defining models. / Provider ${providerName}: \"apiKey\" is required when defining custom models unless auth is \"none\" or \"oauth\".","messagePattern":"Provider (.+?): \"apiKey\" or \"oauth\" is required when defining models\\. / Provider (.+?): \"apiKey\" is required when defining custom models unless auth is \"none\" or \"oauth\"\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/config/models-config.ts","lineNumber":73,"sourceCode":"\t\t\t\t!config.remoteCompaction &&\n\t\t\t\t!hasModelOverrides &&\n\t\t\t\t!config.discovery\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Provider ${providerName}: must specify \"baseUrl\", \"headers\", \"apiKey\", \"auth: none\", \"compat\", \"disableStrictTools\", \"guardrailIdentifier\", \"remoteCompaction\", \"modelOverrides\", \"discovery\", or \"models\"`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif (!config.baseUrl) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"baseUrl\" is required when defining custom models.`);\n\t\t}\n\t\tconst requiresAuth =\n\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);","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/config/models-config.ts#L55-L91","documentation":"validateProviderConfiguration enforces credentials for providers that define models. Two variants: in runtime-register mode, either `apiKey` or a configured OAuth login (`oauthConfigured`) must exist; in models-config mode, `apiKey` must be present unless `auth` is \"none\" or \"oauth\". The error is thrown when models are defined but no usable credential path exists.","triggerScenarios":"registerProvider(name, { baseUrl, models }) at runtime without apiKey and without prior OAuth login; or a models-config provider with models but no apiKey and auth unset/defaulting to \"apiKey\" (also fires when auth is a value other than none/oauth and apiKey is missing).","commonSituations":"Pointing at a local server (Ollama/llama.cpp/vLLM) that needs no key but forgetting `auth: \"none\"`; OAuth previously done via /login was cleared so oauthConfigured is false; apiKey defined under a wrong key name (token, api_key); env-var expansion in the config failed leaving an empty key.","solutions":["For keyless local servers, add `\"auth\": \"none\"` to the provider config (models-config mode).","Otherwise set `apiKey` (or fix its key name / env expansion so it is non-empty).","For OAuth providers, complete the /login flow so oauthConfigured is true before registering models.","In SDK/runtime code, pass apiKey in the ProviderConfigInput or set oauthConfigured."],"exampleFix":"// before: keyless local server\n{ \"provider\": \"local\", \"baseUrl\": \"http://localhost:11434/v1\", \"models\": [{ \"id\": \"qwen3\" }] }\n// after\n{ \"provider\": \"local\", \"baseUrl\": \"http://localhost:11434/v1\", \"auth\": \"none\", \"models\": [{ \"id\": \"qwen3\" }] }","handlingStrategy":"validation","validationCode":"function providerHasCredentialPath(cfg: { apiKey?: string; auth?: string; oauthConfigured?: boolean; mode: \"runtime-register\" | \"models-config\" }): boolean {\n  if (cfg.mode === \"runtime-register\") return Boolean(cfg.apiKey || cfg.oauthConfigured);\n  const auth = cfg.auth ?? \"apiKey\";\n  return Boolean(cfg.apiKey) || auth === \"none\" || auth === \"oauth\";\n}","typeGuard":"null","tryCatchPattern":"try {\n  modelsConfig.apply(parsed);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('\"apiKey\" or \"oauth\" is required')) {\n    const provider = err.message.match(/Provider ([^:]+):/)?.[1];\n    throw new Error(`Set apiKey or auth:\"none\" for provider \"${provider}\"`);\n  }\n  throw err;\n}","preventionTips":["Add auth:\"none\" to keyless local providers (Ollama, llama.cpp, vLLM).","Verify env-var expansion leaves apiKey non-empty; empty strings still count as missing.","Complete OAuth /login before relying on oauth in runtime-register mode.","Check credential path with providerHasCredentialPath before loading config."],"tags":["configuration","authentication","api-key","validation"],"backgroundTag":"missing-api-key","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}