{"record":{"id":"d6e77259b08df444","repo":"BigPizzaV3/CodexPlusPlus","slug":"chat-completions-key","errorCode":null,"errorMessage":"Chat Completions 上游 Key 不能为空","messagePattern":"Chat Completions 上游 Key 不能为空","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/protocol_proxy.rs","lineNumber":1071,"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() && !relay.uses_no_auth() {\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 request = 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    .header(reqwest::header::CONTENT_TYPE, \"application/json\")\n    .json(&request_json);\n    let upstream = with_relay_auth(request, &relay).send().await?;\n    let status_code = upstream.status().as_u16();\n    let content_type = upstream\n        .headers()","sourceCodeStart":1053,"sourceCodeEnd":1089,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/protocol_proxy.rs#L1053-L1089","documentation":"The Chat Completions proxy requires an upstream API key unless the profile is in no-auth mode. It bails when relay.api_key is empty/whitespace and uses_no_auth() is false, so the forwarded request always carries credentials when the upstream expects them.","triggerScenarios":"Chat Completions proxy request arrives with active_relay_profile().api_key blank and uses_no_auth() false.","commonSituations":"New Chat Completions profile without a key; key removed during edit; copying a local no-auth profile to point at a real paid upstream.","solutions":["Set the Chat Completions 上游 Key (api_key) in the active relay profile","Enable the profile's no-auth option if the upstream truly needs no key","Re-apply the profile and retry"],"exampleFix":"// before\napi_key = \"\"\n// after\napi_key = \"sk-...\"","handlingStrategy":"validation","validationCode":"if relay.api_key.trim().is_empty() && !relay.uses_no_auth() { return Err(\"chat completions upstream api key missing\"); }","typeGuard":null,"tryCatchPattern":"match proxy_chat_completions(...) {\n    Err(e) if e.to_string().contains(\"Key 不能为空\") => eprintln!(\"请填写 Chat Completions 上游 Key: {e}\"),\n    other => other?,\n}","preventionTips":["Enter the key when creating chat_completions profiles","Use no-auth mode only for keyless upstreams","Verify key presence after each profile edit"],"tags":["config","validation","api-key","auth"],"backgroundTag":"missing-api-key","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}