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
- 在 profile 设置中填入有效的 sub2api API Key 后重试
- 在 UI/配置层保存时强制校验 api_key 非空
- 若仅探测连通性,可改用无需鉴权的健康检查端点
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
- 保存 profile 时强制校验 api_key 非空
- 配置脱敏导出后导入时提醒补填 Key
- 轮换密钥时同步更新本库 profile
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
- 请在设置中填写有效 API Key
- Chat Completions 上游 Key 不能为空
- 上游 Key 不能为空
- 图片上游 Key 不能为空
- 官方混合 API 不应在 auth.json 中保存 OPENAI_API_KEY。请清理此供应商的…
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)