{"record":{"id":"0a3c99ec8696d5aa","repo":"BigPizzaV3/CodexPlusPlus","slug":"base-url-0a3c99","errorCode":null,"errorMessage":"图片上游 Base URL 不能为空","messagePattern":"图片上游 Base URL 不能为空","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/protocol_proxy.rs","lineNumber":992,"sourceCode":"\nasync fn open_image_proxy_request(\n    body: &[u8],\n    content_type: &str,\n    original_user_agent: Option<&str>,\n    endpoint_kind: ImageProxyEndpoint,\n) -> anyhow::Result<UpstreamProxyResponse> {\n    let settings = SettingsStore::default().load().unwrap_or_default();\n    let relay = crate::relay_rotation::select_relay_for_probe(&settings)?;\n    let base_url = if relay.upstream_base_url.trim().is_empty() {\n        crate::relay_config::relay_profile_base_url(&relay)\n    } else {\n        relay.upstream_base_url.trim().to_string()\n    };\n    if is_local_protocol_proxy_base_url(&base_url) {\n        anyhow::bail!(\"图片上游 Base URL 不能指向本地协议代理\");\n    }\n    if base_url.trim().is_empty() {\n        anyhow::bail!(\"图片上游 Base URL 不能为空\");\n    }\n    if relay.api_key.trim().is_empty() && !relay.uses_no_auth() {\n        anyhow::bail!(\"图片上游 Key 不能为空\");\n    }\n    let content_type = content_type.trim();\n    let content_type = if content_type.is_empty() {\n        match endpoint_kind {\n            ImageProxyEndpoint::Generations => \"application/json\",\n            ImageProxyEndpoint::Edits => {\n                anyhow::bail!(\"图片 edits 请求缺少 Content-Type\");\n            }\n        }\n    } else {\n        content_type\n    };\n    let endpoint = endpoint_kind.url(&base_url);\n    let wire_api = endpoint_kind.wire_api();\n    let _ = crate::diagnostic_log::append_diagnostic_log(","sourceCodeStart":974,"sourceCodeEnd":1010,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/protocol_proxy.rs#L974-L1010","documentation":"open_image_proxy_request requires a non-empty upstream base URL for image API requests. After resolving the effective base URL and rejecting local proxy addresses, it bails if the URL is still empty/whitespace. This prevents issuing requests with an unusable upstream endpoint.","triggerScenarios":"Calling open_image_generations_proxy_request or open_image_edits_proxy_request when both relay.upstream_base_url is blank/whitespace and the relay_profile_base_url fallback also yields an empty string.","commonSituations":"Freshly created relay profile with no upstream URL configured; profile field cleared in the manager UI; settings file migrated without the upstream_base_url key.","solutions":["Fill in the 图片上游 Base URL field in the active relay profile with a valid https:// endpoint","Verify the settings file (active relay profile) actually contains upstream_base_url or a base_url the fallback can use","Re-apply the relay profile after editing"],"exampleFix":"// before\nupstream_base_url = \"\"\n// after\nupstream_base_url = \"https://api.openai.com\"","handlingStrategy":"validation","validationCode":"let base = if relay.upstream_base_url.trim().is_empty() { crate::relay_config::relay_profile_base_url(&relay) } else { relay.upstream_base_url.trim().to_string() };\nif base.trim().is_empty() { return Err(\"upstream base url is empty\"); }","typeGuard":null,"tryCatchPattern":"match open_image_edits_proxy_request(...) {\n    Err(e) if e.to_string().contains(\"Base URL 不能为空\") => eprintln!(\"请先在当前中转配置图片上游 Base URL: {e}\"),\n    other => other?,\n}","preventionTips":["Always fill upstream_base_url when creating a profile","Add a save-time check in the UI rejecting empty URLs","Audit profiles after settings migrations for blank fields"],"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"}