BigPizzaV3/CodexPlusPlus · error

Chat Completions 上游 Key 不能为空

Error message

Chat Completions 上游 Key 不能为空

What it means

The Chat Completions proxy requires an upstream API key unless the profile is in no-auth mode. It bails when relay.api_key is empty/whitespace and uses_no_auth() is false, so the forwarded request always carries credentials when the upstream expects them.

Solutions

  1. Set the Chat Completions 上游 Key (api_key) in the active relay profile
  2. Enable the profile's no-auth option if the upstream truly needs no key
  3. Re-apply the profile and retry

Example fix

// before
api_key = ""
// after
api_key = "sk-..."
Defensive patterns

Strategy: validation

Validate before calling

if relay.api_key.trim().is_empty() && !relay.uses_no_auth() { return Err("chat completions upstream api key missing"); }

Try / catch

match proxy_chat_completions(...) {
    Err(e) if e.to_string().contains("Key 不能为空") => eprintln!("请填写 Chat Completions 上游 Key: {e}"),
    other => other?,
}

Prevention

When it happens

Trigger: Chat Completions proxy request arrives with active_relay_profile().api_key blank and uses_no_auth() false.

Common situations: New Chat Completions profile without a key; key removed during edit; copying a local no-auth profile to point at a real paid upstream.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/d6e77259b08df444. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-core/src/protocol_proxy.rs:1071

    } 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?;
    let status_code = upstream.status().as_u16();
    let content_type = upstream
        .headers()

View on GitHub (pinned to b1ed92e5e4)