BigPizzaV3/CodexPlusPlus · error

API Key 不能为空

Error message

API Key 不能为空

What it means

In the same function, the trimmed profile.api_key is checked next; an empty key triggers this bail. The billing endpoint requires bearer/x-api-key auth, and calling it without a key would only yield a 401 from the server, so it is rejected locally.

Solutions

  1. 在 profile 设置中填入有效的 sub2api API Key 后重试
  2. 在 UI/配置层保存时强制校验 api_key 非空
  3. 若仅探测连通性,可改用无需鉴权的健康检查端点

Example fix

// before
let info = fetch_sub2api_billing_info(&profile).await?;
// after
if profile.api_key.trim().is_empty() {
    eprintln!("请先填写 API Key");
    return Ok(None);
}
let info = fetch_sub2api_billing_info(&profile).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn api_key_ready(p: &RelayProfile) -> bool {
    !p.api_key.trim().is_empty()
}

Try / catch

if !api_key_ready(&profile) {
    eprintln!("请先填写 sub2api API Key");
    return Ok(None);
}
let info = fetch_sub2api_billing_info(&profile).await?;

Prevention

When it happens

Trigger: profile.api_key 为空字符串或纯空白时调用 fetch_sub2api_billing_info。

Common situations: 用户未在 profile 中填写 API Key 就点查询倍率;导出的配置脱敏后丢失 Key;Key 被误删或换号后未更新。

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

Appendix: source

Thrown at crates/codex-plus-core/src/sub2api.rs:52

    applied_peak_multiplier: Option<f64>,
    effective_rate_multiplier: f64,
    observed_at: String,
}

pub async fn fetch_sub2api_billing_info(
    profile: &RelayProfile,
) -> anyhow::Result<Sub2ApiBillingInfo> {
    let base_url = if profile.upstream_base_url.trim().is_empty() {
        profile.base_url.trim()
    } else {
        profile.upstream_base_url.trim()
    };
    if base_url.is_empty() {
        anyhow::bail!("Base URL 不能为空");
    }
    let api_key = profile.api_key.trim();
    if api_key.is_empty() {
        anyhow::bail!("API Key 不能为空");
    }

    let endpoint = sub2api_billing_endpoint(base_url);
    let client = crate::http_client::proxied_client(&profile.user_agent)?;
    let response = client
        .get(&endpoint)
        .bearer_auth(api_key)
        .header("x-api-key", api_key)
        .send()
        .await
        .with_context(|| format!("请求 {endpoint} 失败"))?;
    let status = response.status();
    let body = response.text().await.unwrap_or_default();
    if !status.is_success() {
        anyhow::bail!(
            "HTTP {}:{}",
            status.as_u16(),
            sub2api_error_message(&body).unwrap_or_else(|| "上游拒绝读取倍率".to_string())

View on GitHub (pinned to b1ed92e5e4)