BigPizzaV3/CodexPlusPlus · error · anyhow::Error
{key} must be a TOML table
Error message
{key} must be a TOML table What it means
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).
Source
Thrown at crates/codex-plus-core/src/computer_use_guard.rs:758
if contents.trim().is_empty() {
Ok(DocumentMut::new())
} else {
contents
.parse::<DocumentMut>()
.with_context(|| "config.toml TOML parse failed")
}
}
fn table_mut_or_insert<'a>(doc: &'a mut DocumentMut, key: &str) -> anyhow::Result<&'a mut Table> {
if !doc.as_table().contains_key(key) {
doc[key] = toml_edit::table();
}
if doc.get(key).and_then(Item::as_table).is_none() {
doc[key] = toml_edit::table();
}
doc.get_mut(key)
.and_then(Item::as_table_mut)
.ok_or_else(|| anyhow::anyhow!("{key} must be a TOML table"))
}
fn ensure_plugin_enabled(doc: &mut DocumentMut, plugin_id: &str) -> anyhow::Result<()> {
let plugins = table_mut_or_insert(doc, "plugins")?;
if !plugins.contains_key(plugin_id) {
plugins[plugin_id] = toml_edit::table();
}
if plugins.get(plugin_id).and_then(Item::as_table).is_none() {
plugins[plugin_id] = toml_edit::table();
}
plugins[plugin_id]["enabled"] = toml_edit::value(true);
Ok(())
}
fn ensure_trailing_newline(mut contents: String) -> String {
if !contents.ends_with('\n') {
contents.push('\n');
}View on GitHub (pinned to 1f431ae49b)
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
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check the TOML shape before mutating
let doc: toml_edit::DocumentMut = text.parse()?;
ensure!(doc.get(key).map_or(true, |item| item.is_table()),
"{key} exists but is not a table — fix config.toml manually");
let table = table_mut_or_insert(&mut doc, key)?; Type guard
fn toml_key_is_table_or_absent(doc: &toml_edit::DocumentMut, key: &str) -> bool {
match doc.get(key) { None => true, Some(item) => item.is_table() }
} Try / catch
match table_mut_or_insert(&mut doc, key) {
Ok(t) => Ok(t),
Err(e) if e.to_string().contains("must be a TOML table") => {
// defensive branch tripped — rebuild the document from scratch rather than trusting it
let mut fresh = toml_edit::DocumentMut::new();
fresh[key] = toml_edit::table();
// …re-apply intended edits to `fresh`…
Ok(fresh[key].as_table_mut().unwrap())
}
Err(e) => Err(e),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- config.toml TOML parse failed: {error}
- invalid @oai/sky package.json path
- invalid runtime file path
- invalid bundled marketplace path
- {table_name} 必须是 TOML 表
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16).
Data as JSON: /api/errors/4503b7c4563e5e30.
Report an issue: GitHub.