BigPizzaV3/CodexPlusPlus · error · anyhow::Error
auth.json 必须是 JSON 对象
Error message
auth.json 必须是 JSON 对象
What it means
set_openai_api_key_in_auth_contents 负责把 API Key 写入 auth.json JSON(或空 key 时移除 OPENAI_API_KEY 键)。当前实现里非对象 JSON 会在进入分支前被重置为 json!({})(2113-2115 行),因此末尾的 bail「auth.json 必须是 JSON 对象」在当前版本中是防御性死代码,正常不可达;它只在旧版本二进制或该段逻辑被改动后才会出现。JSON 解析失败走的是另一条消息「auth.json JSON 解析失败」。
Source
Thrown at crates/codex-plus-core/src/relay_config.rs:2126
let mut auth = if auth_contents.trim().is_empty() {
json!({})
} else {
serde_json::from_str::<Value>(auth_contents).with_context(|| "auth.json JSON 解析失败")?
};
if !auth.is_object() {
auth = json!({});
}
if let Some(auth_object) = auth.as_object_mut() {
if api_key.trim().is_empty() {
auth_object.remove("OPENAI_API_KEY");
} else {
auth_object.insert(
"OPENAI_API_KEY".to_string(),
Value::String(api_key.trim().to_string()),
);
}
} else {
anyhow::bail!("auth.json 必须是 JSON 对象");
}
Ok(serde_json::to_string_pretty(&auth)?)
}
fn set_experimental_bearer_token_in_config(
config_contents: &str,
api_key: &str,
) -> anyhow::Result<String> {
let mut doc = parse_toml_document(config_contents)?;
let provider_id = active_or_default_provider_id(&doc);
let provider = ensure_provider_table(&mut doc, &provider_id)?;
if api_key.trim().is_empty() {
provider.remove("experimental_bearer_token");
} else {
provider["experimental_bearer_token"] = toml_edit::value(api_key.trim());
}
Ok(move_model_providers_before_profiles(
&ensure_trailing_newline(doc.to_string()),View on GitHub (pinned to 1f431ae49b)
Solutions
- 把 auth.json 修为 JSON 对象(如 {} 或 {"OPENAI_API_KEY": "sk-..."})
- 升级到当前版本(非对象会被自动重置为 {} 而不再报错)
- 写入前用 serde_json 校验根节点 is_object()
Example fix
// before (auth.json)
["sk-abc"]
// after (auth.json)
{
"OPENAI_API_KEY": "sk-abc"
} Defensive patterns
Strategy: validation
Validate before calling
fn is_json_object_or_empty(text: &str) -> bool {
let t = text.trim();
t.is_empty()
|| serde_json::from_str::<serde_json::Value>(t)
.map(|v| v.is_object())
.unwrap_or(false)
}
anyhow::ensure!(is_json_object_or_empty(&auth_contents), "auth.json 必须是 JSON 对象"); Type guard
fn auth_contents_is_object(text: &str) -> bool {
serde_json::from_str::<serde_json::Value>(text)
.map(|v| v.is_object())
.unwrap_or(false)
} Try / catch
if let Err(err) = apply_relay_profile_to_home_with_switch_rules_and_computer_use_guard(&home, &profile, &common, guard) {
if err.to_string().contains("auth.json 必须是 JSON 对象") {
// 当前版本该分支不可达;若出现说明运行的是旧二进制或代码被改动,先升级再排查
}
} Prevention
- auth.json 始终保持 JSON 对象结构
- 手工编辑 auth.json 后用 JSON 校验
- 升级到当前版本可避免该旧版防御分支
When it happens
Trigger: auth_contents 是合法 JSON 但根节点不是对象(数组/字符串/数字),且运行的是未做非对象重置的旧版本;当前代码路径下此 bail 不可达(非对象已被替换为 {})。
Common situations: 用户手工把 auth.json 改成数组或字符串;使用旧版 CodexPlusPlus 二进制;其他工具写入非对象 auth.json。
Related errors
- 官方混合 API 不应在 auth.json 中保存 OPENAI_API_KEY。请清理此供应商的 auth.json
- {} must be a JSON object
- 中转 Key 不能为空
- config.toml 内容不能为空
- {table_name} 必须是 TOML 表
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16).
Data as JSON: /api/errors/53ee88a86cda188b.
Report an issue: GitHub.