{"record":{"id":"f188646ecbdf69ae","repo":"BigPizzaV3/CodexPlusPlus","slug":"chat-completions-base-url","errorCode":null,"errorMessage":"Chat Completions 上游 Base URL 不能为空","messagePattern":"Chat Completions 上游 Base URL 不能为空","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"crates/codex-plus-core/src/protocol_proxy.rs","lineNumber":875,"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() {\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)","sourceCodeStart":857,"sourceCodeEnd":893,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/protocol_proxy.rs#L857-L893","documentation":"Thrown by open_chat_completions_proxy_request in crates/codex-plus-core/src/protocol_proxy.rs when the active relay profile is configured for the Chat Completions protocol but its base_url field is empty (or whitespace-only). Without a base URL the proxy cannot construct the upstream chat completions URL, so it aborts before sending anything.","triggerScenarios":"Calling the chat completions proxy with an active ChatCompletions profile whose base_url was never filled in or was cleared; importing a provider definition that omitted baseUrl; settings file edited by hand leaving an empty string.","commonSituations":"Newly created provider profile saved before entering the endpoint; profile import from URL/query missing the baseUrl parameter; user cleared the field intending to switch providers later but the profile stayed active.","solutions":["Open the active provider profile and fill in the upstream Base URL (e.g. https://api.vendor.com)","Ensure trailing slashes are fine (they are trimmed) but the URL must be non-empty and should include scheme and host","If importing from a share link, include the baseUrl query parameter"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn chat_relay_ready(relay: &RelayProfile) -> bool {\n    relay.protocol == RelayProtocol::ChatCompletions && !relay.base_url.trim().is_empty()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Require a non-empty base URL before a ChatCompletions profile can be activated","Validate imported providers for baseUrl presence before they enter the pool"],"tags":["chat-completions","missing-config","base-url","relay-profile"],"backgroundTag":"missing-base-url-config","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}