{"record":{"id":"95d5b034e60e32eb","repo":"BigPizzaV3/CodexPlusPlus","slug":"model-providers-provider-id-toml-table","errorCode":null,"errorMessage":"model_providers.{provider_id} 必须是 TOML table","messagePattern":"model_providers\\.(.+?) 必须是 TOML table","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/relay_config.rs","lineNumber":3328,"sourceCode":"}\n\nfn ensure_provider_table<'a>(\n    doc: &'a mut DocumentMut,\n    provider_id: &str,\n) -> anyhow::Result<&'a mut Table> {\n    let providers = table_mut_or_insert(doc, \"model_providers\")?;\n    if !providers.contains_key(provider_id)\n        || providers\n            .get(provider_id)\n            .and_then(Item::as_table)\n            .is_none()\n    {\n        providers.insert(provider_id, toml_edit::table());\n    }\n    providers\n        .get_mut(provider_id)\n        .and_then(Item::as_table_mut)\n        .ok_or_else(|| anyhow::anyhow!(\"model_providers.{provider_id} 必须是 TOML table\"))\n}\n\nfn remove_provider_table(doc: &mut DocumentMut, provider_id: &str) {\n    if let Some(providers) = doc.get_mut(\"model_providers\").and_then(Item::as_table_mut) {\n        providers.remove(provider_id);\n        if providers.is_empty() {\n            doc.as_table_mut().remove(\"model_providers\");\n        }\n    }\n}\n\nfn retain_only_provider_table(doc: &mut DocumentMut, provider_id: &str) {\n    if let Some(providers) = doc.get_mut(\"model_providers\").and_then(Item::as_table_mut) {\n        let provider = providers\n            .remove(provider_id)\n            .unwrap_or_else(toml_edit::table);\n        providers.clear();\n        providers.insert(provider_id, provider);","sourceCodeStart":3310,"sourceCodeEnd":3346,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/relay_config.rs#L3310-L3346","documentation":"The provider-table helper inserts model_providers.<provider_id> if absent, then requires the entry to be a mutable TOML table. If the entry exists but holds a non-table value (string, integer, array), as_table_mut returns None and it throws \"model_providers.{provider_id} 必须是 TOML table\". Unlike error 461 (read-only patch), this one tries to create the provider first but cannot overwrite an existing wrong-typed value.","triggerScenarios":"Any apply/write flow that ensures a provider exists when config.toml contains e.g. `model_providers.openai = \"https://...\"` or `[model_providers]` declared as an array of tables `[[model_providers]]` with that id.","commonSituations":"Users converting a provider into a bare base_url string to 'simplify' the config, following old docs that used array-of-tables syntax, or corrupted sections after manual merges.","solutions":["Replace the scalar entry for the named provider with a proper table: [model_providers.<provider_id>] with key/value fields.","If using [[model_providers]] array-of-tables syntax, rewrite as [model_providers.<id>] named tables.","Delete the bad entry and re-apply the profile so the helper inserts a fresh empty table.","Validate config.toml structure (each model_providers child must be a table) before running apply."],"exampleFix":"// before (config.toml)\nmodel_providers.openai = \"https://api.openai.com/v1\"\n// after (config.toml)\n[model_providers.openai]\nbase_url = \"https://api.openai.com/v1\"","handlingStrategy":"validation","validationCode":"fn provider_entry_is_table(doc: &toml_edit::DocumentMut, id: &str) -> bool {\n    doc.get(\"model_providers\")\n        .and_then(|p| p.get(id))\n        .map(|i| i.is_table())\n        .unwrap_or(true) // absent is fine: helper will insert it\n}","typeGuard":"fn as_provider_table(item: Option<&toml_edit::Item>) -> Option<&toml_edit::Table> {\n    item.and_then(|i| i.as_table())\n}","tryCatchPattern":"match apply_relay_profile_to_home(...) {\n    Err(e) if e.to_string().contains(\"必须是 TOML table\") => {\n        // remove the scalar model_providers.<id> entry, re-apply to recreate it as a table\n    }\n    other => other?,\n}","preventionTips":["Always declare providers as [model_providers.<id>] tables, never scalars or [[array]] entries","Validate each model_providers child is a table after external edits","Let the library create provider entries instead of hand-writing them","Diff config.toml against a known-good backup after manual restructuring"],"tags":["toml","config","type-mismatch"],"backgroundTag":"config-type-mismatch","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}