BigPizzaV3/CodexPlusPlus · warning · anyhow::Error

供应商「{}」缺少独立 config.toml,已停止切换,避免继续显示上一套配置文件。

Error message

供应商「{}」缺少独立 config.toml,已停止切换,避免继续显示上一套配置文件。

What it means

validate_switch_profile_files 在真正写入前检查目标 profile:非 Aggregate 模式的 profile 必须自带非空 config_contents,否则 bail 并停止切换。设计意图是保护现场——不切过去,避免 Codex 继续显示上一家供应商的 config.toml/auth.json 造成「界面是 A、实际是 B」的错位。此时未发生任何写入。

Source

Thrown at crates/codex-plus-core/src/relay_switch.rs:169

            settings.computer_use_guard_enabled,
        )?
    };
    let status = relay_config_status_from_home(home);
    if relay.relay_mode == RelayMode::PureApi && !status.configured {
        anyhow::bail!(
            "纯 API 配置写入后未检测到完整 custom provider,请检查 config.toml 和供应商 API Key。"
        );
    }
    Ok(RelaySwitchResult {
        settings: settings.clone(),
        configured: status.configured,
        backup_path: result.backup_path,
    })
}

fn validate_switch_profile_files(profile: &crate::settings::RelayProfile) -> anyhow::Result<()> {
    if profile.relay_mode != RelayMode::Aggregate && profile.config_contents.trim().is_empty() {
        anyhow::bail!(
            "供应商「{}」缺少独立 config.toml,已停止切换,避免继续显示上一套配置文件。",
            if profile.name.trim().is_empty() {
                profile.id.as_str()
            } else {
                profile.name.as_str()
            }
        );
    }
    if profile.relay_mode == RelayMode::Official
        && serde_json::from_str::<serde_json::Value>(&profile.auth_contents)
            .ok()
            .and_then(|value| {
                value
                    .get("OPENAI_API_KEY")
                    .and_then(serde_json::Value::as_str)
                    .map(str::trim)
                    .map(str::is_empty)
            })

View on GitHub (pinned to 1f431ae49b)

Solutions

  1. 先对该 profile 打开编辑器并保存一次,让其生成 config.toml 内容
  2. 检查 settings.json 中该 profile 的 config_contents 字段是否存在且非空
  3. 若确属聚合型供应商,把 relay_mode 改为 Aggregate(聚合模式不要求独立 config)
Defensive patterns

Strategy: validation

Validate before calling

fn profile_has_standalone_config(profile: &RelayProfile) -> bool {
    profile.relay_mode == RelayMode::Aggregate
        || !profile.config_contents.trim().is_empty()
}
anyhow::ensure!(profile_has_standalone_config(&profile), "供应商「{}」缺少独立 config.toml", profile.name);

Type guard

fn is_switchable_profile(profile: &RelayProfile) -> bool {
    profile.relay_mode == RelayMode::Aggregate || !profile.config_contents.trim().is_empty()
}

Try / catch

match switch_relay_profile_in_home(&store, &home, next, &prev) {
    Ok(r) => Ok(r),
    Err(err) if err.to_string().contains("缺少独立 config.toml") => {
        // 安全拒绝:未写入任何文件。引导用户先保存/应用该 profile 生成 config 再切换
        Err(err)
    }
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: switch_relay_profile_in_home 切换到 relay_mode != Aggregate 且 config_contents.trim() 为空的 profile(Relay / PureApi / Official 等需要独立 config 的模式)。消息中的名称取 profile.name,为空则回退用 profile.id。

Common situations: 新建供应商后没点过「保存/应用」,config_contents 从未生成;导入的 profile 数据不完整;settings.json 手工编辑时丢失 config_contents 字段;数据迁移未带上该字段。

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16). Data as JSON: /api/errors/29460f610890e9b6. Report an issue: GitHub.