BigPizzaV3/CodexPlusPlus · error
Chat Completions 上游 Base URL 不能为空
Error message
Chat Completions 上游 Base URL 不能为空
What it means
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.
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
Example fix
// before base_url = "" // after base_url = "https://api.openai.com"
Defensive patterns
Strategy: validation
Validate before calling
if relay.base_url.trim().is_empty() { return Err("chat completions upstream base url is empty"); } Try / catch
match proxy_chat_completions(...) {
Err(e) if e.to_string().contains("Base URL 不能为空") => eprintln!("请填写 Chat Completions 上游 Base URL: {e}"),
other => other?,
} Prevention
- Fill base_url for every chat_completions profile
- Validate required fields on profile save
- Re-apply profiles after editing
When it happens
Trigger: Chat Completions proxy request arrives while active_relay_profile().base_url is empty or whitespace after trim.
Common situations: 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.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/f188646ecbdf69ae.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/protocol_proxy.rs:1068
fn response_header_timeout(is_stream: bool) -> Duration {
if is_stream {
UPSTREAM_STREAM_HEADER_TIMEOUT
} else {
UPSTREAM_HEADER_TIMEOUT
}
}
pub async fn open_chat_completions_proxy_request(
body: &str,
original_user_agent: Option<&str>,
) -> anyhow::Result<UpstreamProxyResponse> {
let settings = SettingsStore::default().load().unwrap_or_default();
let relay = settings.active_relay_profile();
if relay.protocol != RelayProtocol::ChatCompletions {
anyhow::bail!("当前中转未启用 Chat Completions 协议代理");
}
if relay.base_url.trim().is_empty() {
anyhow::bail!("Chat Completions 上游 Base URL 不能为空");
}
if relay.api_key.trim().is_empty() && !relay.uses_no_auth() {
anyhow::bail!("Chat Completions 上游 Key 不能为空");
}
let request_json: Value = serde_json::from_str(body)?;
let is_stream = request_json
.get("stream")
.and_then(Value::as_bool)
.unwrap_or(false);
let request = crate::http_client::proxied_client(&effective_user_agent(
&relay.user_agent,
original_user_agent,
))?
.post(chat_completions_url(&relay.base_url))
.header(reqwest::header::CONTENT_TYPE, "application/json")
.json(&request_json);
let upstream = with_relay_auth(request, &relay).send().await?;View on GitHub (pinned to b1ed92e5e4)