{"record":{"id":"66c28599a7d0e76c","repo":"continuedev/continue","slug":"model-modelname-does-not-have-an-apikeylocation","errorCode":null,"errorMessage":"Model ${modelName} does not have an apiKeyLocation or envSecretLocations defined","messagePattern":"Model (.+?) does not have an apiKeyLocation or envSecretLocations defined","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/continue-sdk/typescript/src/createOpenAIClient.ts","lineNumber":78,"sourceCode":"\n          const modelName = body.model;\n\n          // Look up the model in the assistant's models\n          const modelConfig = assistantModels?.find(\n            (m) => m?.model === modelName || m?.model.endsWith(modelName),\n          );\n\n          if (!modelConfig) {\n            throw new Error(\n              `Model ${modelName} not found in assistant configuration`,\n            );\n          }\n\n          if (\n            !(\"apiKeyLocation\" in modelConfig) &&\n            !(\"envSecretLocations\" in modelConfig)\n          ) {\n            throw new Error(\n              `Model ${modelName} does not have an apiKeyLocation or envSecretLocations defined`,\n            );\n          }\n\n          const continueProperties: ContinueProperties = {\n            apiKeyLocation: modelConfig.apiKeyLocation,\n            envSecretLocations: modelConfig.envSecretLocations,\n            orgScopeId: organizationId ?? null,\n          };\n\n          // Update the request with the modified body\n          modifiedInit.body = JSON.stringify({\n            ...body,\n            continueProperties,\n          });\n        } catch (e) {\n          // If parsing fails, proceed with the original body\n        }","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/continuedev/continue/blob/5522c6f44ca0ac3528b37244818fbfa39b5af470/packages/continue-sdk/typescript/src/createOpenAIClient.ts#L60-L96","documentation":"createOpenAIClient requires each matched model config to declare where its API key lives; if the model entry has neither apiKeyLocation nor envSecretLocations, it can't build the ContinueProperties and throws.","triggerScenarios":"A model in the assistant config matches the request but its config object lacks both 'apiKeyLocation' and 'envSecretLocations' keys.","commonSituations":"Custom/hand-built model configs, schema drift after upgrading continue-sdk where secret location fields were renamed, or assistant configs from a hub version that omits key metadata.","solutions":["Add apiKeyLocation (e.g. {type:'api'}) or envSecretLocations (e.g. ['MY_API_KEY']) to the model config","Update the assistant config from its source so key metadata is included","Upgrade/downgrade continue-sdk to the version matching the config schema","For BYO-key setups, route the request through a model config that declares its key location"],"exampleFix":"// before\nmodels: [{ model: 'gpt-4o', provider: 'openai' }]\n\n// after\nmodels: [{ model: 'gpt-4o', provider: 'openai', apiKeyLocation: { type: 'api' } }]","handlingStrategy":"type-guard","validationCode":"const ok = models.every(m => 'apiKeyLocation' in m || 'envSecretLocations' in m);","typeGuard":"function hasKeyLocation(m: any): m is { apiKeyLocation?: unknown; envSecretLocations?: unknown } { return 'apiKeyLocation' in m || 'envSecretLocations' in m; }","tryCatchPattern":"try { await client.chat.completions.create(req); } catch (e) { if (/apiKeyLocation/.test(e.message)) throw new Error('Model config missing secret location — update assistant config'); throw e; }","preventionTips":["Always declare apiKeyLocation or envSecretLocations in custom model configs","Regenerate assistant configs after upgrading continue-sdk","Validate configs at startup, not at request time"],"tags":["continue-sdk","api-key","config","models"],"backgroundTag":"missing-api-key-config","analyzedSha":"5522c6f44ca0ac3528b37244818fbfa39b5af470","analyzedAt":"2026-08-27T11:28:54.683Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}