{"record":{"id":"1603c7ff69c87e59","repo":"BigPizzaV3/CodexPlusPlus","slug":"base-url-protocol-proxy","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":989,"sourceCode":"        }\n    }\n}\n\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    };","sourceCodeStart":971,"sourceCodeEnd":1007,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/protocol_proxy.rs#L971-L1007","documentation":"open_image_proxy_request validates the upstream base URL before forwarding an image API (generations/edits) request. If the effective base URL (relay.upstream_base_url, falling back to relay_profile_base_url) resolves to a local protocol-proxy address (loopback/private scheme handled by this proxy itself), it refuses to proceed to prevent a proxy loop. The throw is a pre-flight safety guard in crates/codex-plus-core/src/protocol_proxy.rs.","triggerScenarios":"Calling open_image_generations_proxy_request or open_image_edits_proxy_request while the active relay profile's upstream_base_url (or the profile-derived base URL) points at localhost/127.0.0.1 or another local protocol proxy endpoint.","commonSituations":"User pasted a local relay address (e.g. http://127.0.0.1:port) into the '图片上游 Base URL' field of a relay profile, or relay_profile_base_url fallback resolved to the local proxy because the explicit upstream URL was blank.","solutions":["Set the image upstream base URL in the relay profile to a real remote endpoint (e.g. https://api.openai.com), not a localhost address","If upstream_base_url was intentionally blank, set relay_profile_base_url's source profile to a non-local URL","Restart/re-apply the profile so the generated config no longer points image requests at the local proxy"],"exampleFix":"// before\nupstream_base_url = \"http://127.0.0.1:8317\"\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() || is_local_protocol_proxy_base_url(&base) { return Err(\"fix upstream base url first\"); }","typeGuard":null,"tryCatchPattern":"match open_image_generations_proxy_request(...) {\n    Err(e) if e.to_string().contains(\"不能指向本地协议代理\") => eprintln!(\"配置了本地代理地址，请改为远程上游 URL: {e}\"),\n    other => other?,\n}","preventionTips":["Never set upstream_base_url to a localhost/127.0.0.1 address","Validate the URL scheme/host in the manager UI before saving a profile","After applying a profile, run a health-check request to confirm the upstream is remote"],"tags":["config","validation","proxy-loop","url"],"backgroundTag":"invalid-config-value","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"}