BigPizzaV3/CodexPlusPlus · error

上游 Key 不能为空

Error message

上游 Key 不能为空

What it means

validate_upstream also requires relay.api_key to be non-empty unless the relay profile opts into no-auth mode via uses_no_auth(). This guarantees every forwarded upstream request carries credentials when the upstream requires them.

Solutions

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

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("upstream api key missing"); }

Try / catch

match send_proxied_request(...) {
    Err(e) if e.to_string().contains("上游 Key 不能为空") => eprintln!("请在当前中转填写上游 Key: {e}"),
    other => other?,
}

Prevention

When it happens

Trigger: Any proxy request path that calls validate_upstream while relay.api_key is blank and uses_no_auth() is false.

Common situations: Profile created without pasting an API key; key cleared during edit; reusing a local no-auth profile against a real upstream that requires auth.

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/4943931c336951ca. Report an issue: GitHub.

Appendix: source

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

) -> reqwest::RequestBuilder {
    let mut builder = client
        .post(endpoint)
        .header(reqwest::header::CONTENT_TYPE, "application/json");
    builder = with_relay_auth(builder, relay);
    if is_stream {
        builder = builder
            .header(reqwest::header::ACCEPT, "text/event-stream")
            .header(reqwest::header::CACHE_CONTROL, "no-cache");
    }
    builder.json(upstream_body)
}

fn validate_upstream(relay: &crate::settings::RelayProfile) -> anyhow::Result<()> {
    if relay.base_url.trim().is_empty() {
        anyhow::bail!("上游 Base URL 不能为空");
    }
    if relay.api_key.trim().is_empty() && !relay.uses_no_auth() {
        anyhow::bail!("上游 Key 不能为空");
    }
    Ok(())
}

fn with_relay_auth(
    request: reqwest::RequestBuilder,
    relay: &crate::settings::RelayProfile,
) -> reqwest::RequestBuilder {
    if relay.uses_no_auth() {
        request
    } else {
        request.bearer_auth(relay.api_key.trim())
    }
}

fn conversation_id_from_responses_request(body: &Value) -> Option<String> {
    for key in ["conversation", "conversation_id", "previous_response_id"] {
        if let Some(value) = body.get(key).and_then(Value::as_str) {

View on GitHub (pinned to b1ed92e5e4)