{"record":{"id":"d6e77259b08df444","repo":"BigPizzaV3/CodexPlusPlus","slug":"chat-completions-key","errorCode":null,"errorMessage":"Chat Completions 上游 Key 不能为空","messagePattern":"Chat Completions 上游 Key 不能为空","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"crates/codex-plus-core/src/protocol_proxy.rs","lineNumber":878,"sourceCode":"    } else {\n        UPSTREAM_HEADER_TIMEOUT\n    }\n}\n\npub async fn open_chat_completions_proxy_request(\n    body: &str,\n    original_user_agent: Option<&str>,\n) -> anyhow::Result<UpstreamProxyResponse> {\n    let settings = SettingsStore::default().load().unwrap_or_default();\n    let relay = settings.active_relay_profile();\n    if relay.protocol != RelayProtocol::ChatCompletions {\n        anyhow::bail!(\"当前中转未启用 Chat Completions 协议代理\");\n    }\n    if relay.base_url.trim().is_empty() {\n        anyhow::bail!(\"Chat Completions 上游 Base URL 不能为空\");\n    }\n    if relay.api_key.trim().is_empty() {\n        anyhow::bail!(\"Chat Completions 上游 Key 不能为空\");\n    }\n\n    let request_json: Value = serde_json::from_str(body)?;\n    let is_stream = request_json\n        .get(\"stream\")\n        .and_then(Value::as_bool)\n        .unwrap_or(false);\n    let upstream = crate::http_client::proxied_client(&effective_user_agent(\n        &relay.user_agent,\n        original_user_agent,\n    ))?\n    .post(chat_completions_url(&relay.base_url))\n    .bearer_auth(relay.api_key.trim())\n    .header(reqwest::header::CONTENT_TYPE, \"application/json\")\n    .json(&request_json)\n    .send()\n    .await?;\n    let status_code = upstream.status().as_u16();","sourceCodeStart":860,"sourceCodeEnd":896,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/protocol_proxy.rs#L860-L896","documentation":"Thrown by open_chat_completions_proxy_request in crates/codex-plus-core/src/protocol_proxy.rs when the active Chat Completions relay profile has an empty api_key. The proxy authenticates upstream with bearer_auth(relay.api_key), and it refuses to send an anonymous request rather than failing upstream with a 401.","triggerScenarios":"Chat completions proxy request while the active profile's api_key is blank; provider import that carried an empty apiKey; key field cleared during rotation to a vendor that was never configured.","commonSituations":"Half-configured provider left active; imported share link missing the apiKey parameter; user rotated keys and saved the profile before pasting the new key.","solutions":["Enter the upstream API key in the active provider profile and save","If the key was intentionally left blank for a local gateway that needs no auth, note this proxy still requires a non-empty value — put any placeholder only if your gateway accepts it","Re-import the provider with the apiKey parameter included"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn relay_has_key(relay: &RelayProfile) -> bool {\n    !relay.api_key.trim().is_empty()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Require an API key before activating a ChatCompletions provider","During key rotation, write the new key before re-enabling the profile"],"tags":["chat-completions","missing-config","api-key","authentication"],"backgroundTag":"missing-api-key-config","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}