{"record":{"id":"4503b7c4563e5e30","repo":"BigPizzaV3/CodexPlusPlus","slug":"key-must-be-a-toml-table","errorCode":null,"errorMessage":"{key} must be a TOML table","messagePattern":"(.+?) must be a TOML table","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/computer_use_guard.rs","lineNumber":758,"sourceCode":"    if contents.trim().is_empty() {\n        Ok(DocumentMut::new())\n    } else {\n        contents\n            .parse::<DocumentMut>()\n            .with_context(|| \"config.toml TOML parse failed\")\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_plugin_enabled(doc: &mut DocumentMut, plugin_id: &str) -> anyhow::Result<()> {\n    let plugins = table_mut_or_insert(doc, \"plugins\")?;\n    if !plugins.contains_key(plugin_id) {\n        plugins[plugin_id] = toml_edit::table();\n    }\n    if plugins.get(plugin_id).and_then(Item::as_table).is_none() {\n        plugins[plugin_id] = toml_edit::table();\n    }\n    plugins[plugin_id][\"enabled\"] = toml_edit::value(true);\n    Ok(())\n}\n\nfn ensure_trailing_newline(mut contents: String) -> String {\n    if !contents.ends_with('\\n') {\n        contents.push('\\n');\n    }","sourceCodeStart":740,"sourceCodeEnd":776,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/computer_use_guard.rs#L740-L776","documentation":"table_mut_or_insert (crates/codex-plus-core/src/computer_use_guard.rs:758) ensures a TOML key exists as a table: it inserts toml_edit::table() when the key is absent, overwrites with a fresh table when the existing item is not a table, and then fetches it mutably. The final 'must be a TOML table' error is only reachable if that forced reassignment still yields a non-table — effectively a defensive invariant covering pathological toml_edit document states (e.g. dotted-key indexing quirks or corrupted DocumentMut).","triggerScenarios":"Editing a config.toml whose 'plugins' (or the passed key) entry resists table coercion after the two insert/overwrite attempts — not reproducible with ordinary TOML content since the function unconditionally rewrites the item to a table first.","commonSituations":"Effectively unreachable via user config; would require a code path passing a dotted key string or a DocumentMut built abnormally. If it fires, suspect a code regression in how the key/index is passed, not the file on disk.","solutions":["Log the key and dump the DocumentMut at failure — a key containing '.' or unusual indexing is the prime suspect","Check the caller (ensure_plugin_enabled passes 'plugins') has not started passing composite/dotted keys","Round-trip the file through from_str again to rule out a corrupted in-memory document","Treat any stock-config reproduction as a bug in the guard, not a user config problem"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Pre-check the TOML shape before mutating\nlet doc: toml_edit::DocumentMut = text.parse()?;\nensure!(doc.get(key).map_or(true, |item| item.is_table()),\n    \"{key} exists but is not a table — fix config.toml manually\");\nlet table = table_mut_or_insert(&mut doc, key)?;","typeGuard":"fn toml_key_is_table_or_absent(doc: &toml_edit::DocumentMut, key: &str) -> bool {\n    match doc.get(key) { None => true, Some(item) => item.is_table() }\n}","tryCatchPattern":"match table_mut_or_insert(&mut doc, key) {\n    Ok(t) => Ok(t),\n    Err(e) if e.to_string().contains(\"must be a TOML table\") => {\n        // defensive branch tripped — rebuild the document from scratch rather than trusting it\n        let mut fresh = toml_edit::DocumentMut::new();\n        fresh[key] = toml_edit::table();\n        // …re-apply intended edits to `fresh`…\n        Ok(fresh[key].as_table_mut().unwrap())\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Reject dotted/composite keys at the API boundary of TOML helpers","Re-parse documents from text when invariants trip instead of continuing with suspect state","Keep config keys as plain identifiers ('plugins'), never paths"],"tags":["toml","toml-edit","defensive-invariant","config-mutation"],"backgroundTag":"toml-type-mismatch","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}