BigPizzaV3/CodexPlusPlus · error

活动协议代理需要现有 model_providers.

Error message

活动协议代理需要现有 model_providers.{transport_provider_id} 配置

What it means

ensure_active_protocol_proxy_config_in_home configures the active-protocol proxy by rewriting base_url inside the model_providers.<transport_provider_id> table of config.toml. This error is thrown when that provider entry does not exist (model_providers table missing, or the provider id absent, or it is not a table). The function intentionally does NOT create the provider; it only patches an existing one.

Solutions

  1. Add (or restore) the `[model_providers.<transport_provider_id>]` table in config.toml with a base_url, matching the id reported in the error.
  2. Check the active RelayProfile's transport_provider_id and correct it to an existing provider id in config.toml.
  3. Re-apply the relay profile so CodexPlusPlus writes the provider table before enabling the active-protocol proxy.
  4. Back up and rebuild config.toml from the profile settings to resync provider ids.

Example fix

// before (config.toml) — missing provider
# no [model_providers.deepseek] section
// after (config.toml)
[model_providers.deepseek]
name = "DeepSeek"
base_url = "https://api.deepseek.com/v1"
Defensive patterns

Strategy: validation

Validate before calling

let doc = std::fs::read_to_string("~/.codex/config.toml")?.parse::<toml_edit::DocumentMut>()?;
let ok = doc.get("model_providers")
    .and_then(|p| p.get(transport_provider_id))
    .map(|i| i.is_table())
    .unwrap_or(false);
if !ok { /* create the provider table first */ }

Type guard

fn provider_exists(doc: &toml_edit::DocumentMut, id: &str) -> bool {
    doc.get("model_providers")
        .and_then(|p| p.get(id))
        .map(|i| i.is_table())
        .unwrap_or(false)
}

Try / catch

if let Err(e) = ensure_active_protocol_proxy_config_in_home(...) {
    if e.to_string().contains("需要现有 model_providers") {
        // write the missing [model_providers.<id>] table, then retry
    }
}

Prevention

When it happens

Trigger: Calling the apply flow (apply_relay_profile_to_home_with_switch_rules family) with a profile whose transport_provider_id has no corresponding [model_providers.<id>] table in config.toml — e.g. the provider was deleted, renamed, or the profile references a provider never written by CodexPlusPlus.

Common situations: User manually removed a provider section from config.toml, switched profiles and the target provider id no longer matches, or upgraded the fork and the provider naming scheme changed while old configs remained.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/b7cad3a46f3aba0a. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-core/src/relay_config.rs:323

        .with_context(|| format!("读取 {} 失败", config_path.display()))?;
    let mut doc = parse_toml_document(&existing)?;
    let managed = managed_openai_base_url();
    let mut changed = false;

    if transport_uses_proxy {
        let session_provider_id = active_session_provider_id(&doc);
        let transport_provider_id = if session_provider_id == "openai" {
            RELAY_PROVIDER.to_string()
        } else {
            active_or_default_provider_id(&doc)
        };
        let provider = doc
            .get_mut("model_providers")
            .and_then(Item::as_table_mut)
            .and_then(|providers| providers.get_mut(&transport_provider_id))
            .and_then(Item::as_table_mut)
            .ok_or_else(|| {
                anyhow::anyhow!("活动协议代理需要现有 model_providers.{transport_provider_id} 配置")
            })?;
        let current = provider
            .get("base_url")
            .and_then(Item::as_str)
            .map(str::trim);
        if current != Some(managed.as_str()) {
            provider["base_url"] = toml_edit::value(managed.as_str());
            changed = true;
        }
    }

    if openai_identity_uses_proxy {
        let before = doc
            .get(OPENAI_BASE_URL_KEY)
            .and_then(Item::as_str)
            .map(str::trim)
            .map(ToString::to_string);
        update_remote_control_openai_base_url(&mut doc, true);

View on GitHub (pinned to b1ed92e5e4)