{"record":{"id":"807c6ed638e9f856","repo":"Hmbown/CodeWhale","slug":"bearer-credentials-are-not-an-api-key","errorCode":null,"errorMessage":"bearer credentials are not an API key","messagePattern":"bearer credentials are not an API key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/credential_handoff.rs","lineNumber":40,"sourceCode":"}\n\npub(crate) fn resolve_api_key(\n    store: &ConfigStore,\n    secrets: &Secrets,\n    provider: ProviderKind,\n    runtime_overrides: &CliRuntimeOverrides,\n) -> Result<String> {\n    let resolved = store.config.resolve_runtime_options_with_secrets(\n        &runtime_overrides_for_provider(runtime_overrides, provider),\n        secrets,\n    );\n    if resolved.provider != provider {\n        bail!(\"resolved a different provider\");\n    }\n    let source = resolved.api_key_source;\n    if source != Some(RuntimeApiKeySource::Cli) {\n        if provider == ProviderKind::OpenaiCodex {\n            bail!(\"bearer credentials are not an API key\");\n        }\n        let uses_api_key = provider != ProviderKind::Xai\n            || xai_auth_diagnostics(store, runtime_overrides).evaluates_runtime_api_key();\n        ensure!(uses_api_key, \"OAuth bearer credentials are not an API key\");\n        let kimi_bearer = provider == ProviderKind::Moonshot\n            && resolved\n                .auth_mode\n                .as_deref()\n                .is_some_and(auth_mode_uses_kimi_imported_token);\n        ensure!(!kimi_bearer, \"bearer credentials are not an API key\");\n    }\n    ensure!(source.is_some(), \"no runtime-effective API key\");\n    resolved\n        .api_key\n        .filter(|value| !value.trim().is_empty())\n        .context(\"no usable runtime-effective API key\")\n}\n","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/credential_handoff.rs#L22-L58","documentation":"resolve_api_key only hands off real API keys. When the resolved source is not RuntimeApiKeySource::Cli and the provider is OpenaiCodex, credentials come from bearer/OAuth token storage, which is not an API key, so the handoff bails. For other providers, OAuth bearer credentials are separately rejected by the ensure! on the next lines unless an API key is actually configured.","triggerScenarios":"Requesting an API key for OpenaiCodex while the resolved credential source is a bearer/OAuth token rather than a CLI-provided key; or, for other providers, when only OAuth bearer auth is configured and no API key resolves.","commonSituations":"Logging into Codex via OAuth (`codex` login flow) and then asking the handoff for an API key; xai/moonshot accounts authenticated with OAuth only; scripts expecting a static key but the machine uses token-based auth.","solutions":["Provide an actual API key: `codewhale credential set <provider> <key>` or pass it via the CLI/override so api_key_source becomes Cli.","For OpenaiCodex, use the bearer-token handoff path instead of the API-key handoff — the two credential kinds have separate surfaces.","For xai, ensure an API key is configured (the code checks xai_auth_diagnostics().evaluates_runtime_api_key()); for moonshot, note bearer-only accounts also fail the key check."],"exampleFix":"// before (OAuth-only Codex login)\ncodewhale credential api-key openai-codex   # -> bearer credentials are not an API key\n// after\ncodewhale credential set openai-codex sk-...\ncodewhale credential api-key openai-codex","handlingStrategy":"type-guard","validationCode":"let resolved = store.config.resolve_runtime_options_with_secrets(&overrides, &secrets);\nif resolved.api_key_source != Some(RuntimeApiKeySource::Cli) {\n    eprintln!(\"credential source is not a CLI API key (bearer/OAuth); set an API key for this provider\");\n}\n","typeGuard":"fn has_api_key(resolved: &ResolvedOptions) -> bool {\n    resolved.api_key_source == Some(RuntimeApiKeySource::Cli)\n}","tryCatchPattern":"match resolve_api_key(&store, &overrides, provider) {\n    Err(e) if e.to_string().contains(\"not an API key\") => {\n        eprintln!(\"provider uses OAuth bearer auth; run the token handoff or set an API key\");\n    }\n    other => other,\n}","preventionTips":["Set explicit API keys (`credential set <provider> <key>`) for providers consumed by the key handoff.","Remember OpenaiCodex OAuth login yields bearer tokens, not API keys.","In scripts, check the credential source before expecting a static key."],"tags":["credentials","oauth","api-key","provider"],"backgroundTag":"missing-api-key","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}