Summary
Built-in provider catalog entries declare apiKeyEnvVar, but parseModelConfig does not use that metadata when resolving provider credentials. As a result, a catalog provider/model can inherit catalog protocol, default URL, and model defaults, while still failing with missing_api_key even when the catalog-declared environment variable is set.
Code path
Producer / parser / validator / consumer anchors:
src/model/catalog/types.ts:12-17 defines CatalogProviderEntry.apiKeyEnvVar.
src/model/catalog/providers.ts:7-12 sets apiKeyEnvVar for anthropic as ANTHROPIC_API_KEY.
src/model/catalog/providers.ts:123-128 sets apiKeyEnvVar for openai as OPENAI_API_KEY.
src/model/config/parseModelConfig.ts:70-86 reads the catalog provider and uses catalog defaults for protocol/default URL.
src/model/config/parseModelConfig.ts:103-108 calls resolveApiKey(provider.apiKey, env) without passing catalogProvider.apiKeyEnvVar.
src/model/config/resolveCredentials.ts:18-26 rejects missing/non-string apiKey as missing_api_key.
src/model/config/resolveCredentials.ts:28-42 can resolve explicit ${ENV_VAR} strings from env.
src/model/streaming/streamModel.ts:515-532 sends the parsed provider.apiKey in provider request headers.
Steps to reproduce
Validation level: dynamic minimal reproduction plus source control-flow confirmation.
With ANTHROPIC_API_KEY available in the parser env, parse an Anthropic catalog provider/model without an explicit raw apiKey field:
parseModelConfig(
{
providers: {
anthropic: {
models: {
"claude-sonnet-4-5-20250929": {},
},
},
},
},
{ env: { ANTHROPIC_API_KEY: "sk-test-from-env" } },
);
Observed output from a local tsx reproduction:
ERROR ModelConfigError missing_api_key Provider apiKey must be a non-empty string.
Control case with explicit env reference:
apiKey: "${ANTHROPIC_API_KEY}"
Observed output:
Expected behavior
If catalog provider metadata is intended to provide runtime defaults, apiKeyEnvVar should be projected into credential resolution when provider.apiKey is absent. For example, anthropic could resolve from ANTHROPIC_API_KEY without requiring the user to repeat apiKey: ${ANTHROPIC_API_KEY} in config.
If apiKeyEnvVar is intended to be UI-only metadata rather than runtime credential metadata, the field should be renamed, documented, or otherwise kept out of the runtime-default path so it is not mistaken for an executable contract.
Actual behavior
parseModelConfig consumes adjacent catalog metadata for provider protocol/default URL/model defaults, but ignores catalogProvider.apiKeyEnvVar. The credential validator only receives raw provider.apiKey, so missing raw apiKey fails even when the catalog-declared env var is present.
Existing coverage
Related but not full coverage:
I also checked current issues/PRs for apiKeyEnvVar, resolveApiKey missing_api_key, ANTHROPIC_API_KEY, OPENAI_API_KEY, and parseModelConfig resolveCredentials; no same-root issue/PR was found.
Suggested fix
When provider.apiKey is absent and catalogProvider?.apiKeyEnvVar is set, pass an equivalent env reference into resolveApiKey, or add a small helper such as:
const rawApiKey = provider.apiKey ?? (catalogProvider?.apiKeyEnvVar ? `\${${catalogProvider.apiKeyEnvVar}}` : undefined);
apiKey: resolveApiKey(rawApiKey, env),
The exact shape can vary; the important part is that the catalog credential metadata and runtime credential parser agree on whether this field is executable.
Suggested tests
parseModelConfig resolves Anthropic apiKey from ANTHROPIC_API_KEY when raw apiKey is absent and the provider exists in the catalog.
- The existing explicit
${ENV_VAR} behavior still works.
- Missing raw
apiKey and missing catalog/env value still fails with missing_api_key.
- A provider without catalog
apiKeyEnvVar keeps the current failure behavior.
Submitted with Codex.
Summary
Built-in provider catalog entries declare
apiKeyEnvVar, butparseModelConfigdoes not use that metadata when resolving provider credentials. As a result, a catalog provider/model can inherit catalog protocol, default URL, and model defaults, while still failing withmissing_api_keyeven when the catalog-declared environment variable is set.Code path
Producer / parser / validator / consumer anchors:
src/model/catalog/types.ts:12-17definesCatalogProviderEntry.apiKeyEnvVar.src/model/catalog/providers.ts:7-12setsapiKeyEnvVarforanthropicasANTHROPIC_API_KEY.src/model/catalog/providers.ts:123-128setsapiKeyEnvVarforopenaiasOPENAI_API_KEY.src/model/config/parseModelConfig.ts:70-86reads the catalog provider and uses catalog defaults for protocol/default URL.src/model/config/parseModelConfig.ts:103-108callsresolveApiKey(provider.apiKey, env)without passingcatalogProvider.apiKeyEnvVar.src/model/config/resolveCredentials.ts:18-26rejects missing/non-stringapiKeyasmissing_api_key.src/model/config/resolveCredentials.ts:28-42can resolve explicit${ENV_VAR}strings fromenv.src/model/streaming/streamModel.ts:515-532sends the parsedprovider.apiKeyin provider request headers.Steps to reproduce
Validation level: dynamic minimal reproduction plus source control-flow confirmation.
With
ANTHROPIC_API_KEYavailable in the parser env, parse an Anthropic catalog provider/model without an explicit rawapiKeyfield:Observed output from a local
tsxreproduction:Control case with explicit env reference:
apiKey: "${ANTHROPIC_API_KEY}"Observed output:
Expected behavior
If catalog provider metadata is intended to provide runtime defaults,
apiKeyEnvVarshould be projected into credential resolution whenprovider.apiKeyis absent. For example,anthropiccould resolve fromANTHROPIC_API_KEYwithout requiring the user to repeatapiKey: ${ANTHROPIC_API_KEY}in config.If
apiKeyEnvVaris intended to be UI-only metadata rather than runtime credential metadata, the field should be renamed, documented, or otherwise kept out of the runtime-default path so it is not mistaken for an executable contract.Actual behavior
parseModelConfigconsumes adjacent catalog metadata for provider protocol/default URL/model defaults, but ignorescatalogProvider.apiKeyEnvVar. The credential validator only receives rawprovider.apiKey, so missing rawapiKeyfails even when the catalog-declared env var is present.Existing coverage
Related but not full coverage:
src/model/catalog/*,parseModelConfig,resolveCredentials, or catalog providerapiKeyEnvVarprojection into model runtime credentials.I also checked current issues/PRs for
apiKeyEnvVar,resolveApiKey missing_api_key,ANTHROPIC_API_KEY,OPENAI_API_KEY, andparseModelConfig resolveCredentials; no same-root issue/PR was found.Suggested fix
When
provider.apiKeyis absent andcatalogProvider?.apiKeyEnvVaris set, pass an equivalent env reference intoresolveApiKey, or add a small helper such as:The exact shape can vary; the important part is that the catalog credential metadata and runtime credential parser agree on whether this field is executable.
Suggested tests
parseModelConfigresolves AnthropicapiKeyfromANTHROPIC_API_KEYwhen rawapiKeyis absent and the provider exists in the catalog.${ENV_VAR}behavior still works.apiKeyand missing catalog/env value still fails withmissing_api_key.apiKeyEnvVarkeeps the current failure behavior.Submitted with Codex.