{"record":{"id":"f188646ecbdf69ae","repo":"BigPizzaV3/CodexPlusPlus","slug":"chat-completions-base-url","errorCode":null,"errorMessage":"Chat Completions 上游 Base URL 不能为空","messagePattern":"Chat Completions 上游 Base URL 不能为空","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/protocol_proxy.rs","lineNumber":1068,"sourceCode":"fn response_header_timeout(is_stream: bool) -> Duration {\n    if is_stream {\n        UPSTREAM_STREAM_HEADER_TIMEOUT\n    } 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?;","sourceCodeStart":1050,"sourceCodeEnd":1086,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/protocol_proxy.rs#L1050-L1086","documentation":"After confirming the profile protocol is ChatCompletions, the proxy validates that relay.base_url (the Chat Completions upstream endpoint) is non-empty. An empty URL makes it impossible to forward the request, so it bails before parsing the body.","triggerScenarios":"Chat Completions proxy request arrives while active_relay_profile().base_url is empty or whitespace after trim.","commonSituations":"Profile created with protocol=chat_completions but no upstream URL filled in; base_url cleared during profile editing; settings file missing the base_url key.","solutions":["Set the Chat Completions 上游 Base URL (base_url) in the active relay profile to a valid https:// endpoint","Check the settings file for a missing/blank base_url on the active profile","Re-apply the profile after fixing"],"exampleFix":"// before\nbase_url = \"\"\n// after\nbase_url = \"https://api.openai.com\"","handlingStrategy":"validation","validationCode":"if relay.base_url.trim().is_empty() { return Err(\"chat completions upstream base url is empty\"); }","typeGuard":null,"tryCatchPattern":"match proxy_chat_completions(...) {\n    Err(e) if e.to_string().contains(\"Base URL 不能为空\") => eprintln!(\"请填写 Chat Completions 上游 Base URL: {e}\"),\n    other => other?,\n}","preventionTips":["Fill base_url for every chat_completions profile","Validate required fields on profile save","Re-apply profiles after editing"],"tags":["config","validation","url","empty"],"backgroundTag":"empty-required-field","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"}