{"record":{"id":"58915ccf8846e846","repo":"BigPizzaV3/CodexPlusPlus","slug":"key-must-be-a-toml-table-58915c","errorCode":null,"errorMessage":"{key} must be a TOML table","messagePattern":"(.+?) must be a TOML table","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/plugin_marketplace.rs","lineNumber":859,"sourceCode":"    if contents.trim().is_empty() {\n        Ok(DocumentMut::new())\n    } else {\n        contents\n            .parse::<DocumentMut>()\n            .map_err(|error| anyhow::anyhow!(\"config.toml TOML parse failed: {error}\"))\n    }\n}\n\nfn table_mut_or_insert<'a>(doc: &'a mut DocumentMut, key: &str) -> anyhow::Result<&'a mut Table> {\n    if !doc.as_table().contains_key(key) {\n        doc[key] = toml_edit::table();\n    }\n    if doc.get(key).and_then(Item::as_table).is_none() {\n        doc[key] = toml_edit::table();\n    }\n    doc.get_mut(key)\n        .and_then(Item::as_table_mut)\n        .ok_or_else(|| anyhow::anyhow!(\"{key} must be a TOML table\"))\n}\n\nfn ensure_trailing_newline(mut contents: String) -> String {\n    if !contents.ends_with('\\n') {\n        contents.push('\\n');\n    }\n    contents\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn expected_marketplace_path(path: &Path) -> String {\n        if cfg!(windows) {\n            format!(r\"\\\\?\\{}\", path.display())\n        } else {\n            path.to_string_lossy().into_owned()","sourceCodeStart":841,"sourceCodeEnd":877,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/plugin_marketplace.rs#L841-L877","documentation":"table_mut_or_insert ensures a top-level key in a config.toml DocumentMut is a table, replacing non-conflicting values with a new table, and returns a mutable reference. If the key exists as an array or other non-table item that cannot be coerced (as_table_mut fails after the insert attempt), this error is thrown rather than overwriting user data blindly.","triggerScenarios":"merge_marketplace_configs_and_plugins_into_text calls table_mut_or_insert for a key (e.g. a marketplace or plugin section name) that already exists in config.toml as a non-table TOML value (string, integer, array of tables handled oddly, etc.).","commonSituations":"User declared something like plugins = \"enabled\" instead of [plugins]; a list value conflicts with the expected table; an upstream config writer emitted arrays where tables were expected.","solutions":["Locate the key in config.toml and convert it to a proper table: change `key = value` to `[key]` with sub-keys.","Rename the conflicting key if it was intentional user data, then re-run the merge.","Back up config.toml before merges so a type conflict can be recovered.","Add a pre-merge validation pass that rejects configs with non-table values for managed keys, with a clear message."],"exampleFix":"// before: type conflict\nplugins = true\n// after: table form expected by merge\n[plugins]\nenabled = true","handlingStrategy":"validation","validationCode":"if let Some(v) = doc.get(key) {\n    if v.as_table().is_none() {\n        eprintln!(\"config key '{key}' must be a [table], found: {v}\");\n    }\n}","typeGuard":"fn is_table(doc: &toml_edit::DocumentMut, key: &str) -> bool {\n    doc.get(key).map_or(true, |item| item.as_table().is_some())\n}","tryCatchPattern":"match merge_marketplace_configs_and_plugins_into_text(&config) {\n    Ok(merged) => {},\n    Err(e) if e.to_string().ends_with(\"must be a TOML table\") => {\n        eprintln!(\"{e}; fix the offending key in config.toml to use [section] syntax\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Declare managed keys as [section] tables, never as scalar or array values","Back up config.toml before running merges","Lint config.toml after manual edits to catch type conflicts early"],"tags":["toml","config-merge","type-conflict"],"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"}