Hmbown/CodeWhale · error · anyhow::Error
`{segment}` in config.toml must be a table
Error message
`{segment}` in config.toml must be a table What it means
While walking/creating a dotted config path (set_config_document_value with PathLookup::Create), an existing intermediate segment in config.toml is not a table-like item (it is a scalar, array, or array-of-tables), so it cannot be descended into. The message names the offending top-level segment.
Source
Thrown at crates/config/src/config_document.rs:437
let mut current: &mut dyn toml_edit::TableLike = root;
for segment in segments {
if current.get(segment).is_none() {
match lookup {
PathLookup::Create => {
let mut table = toml_edit::Table::new();
table.set_implicit(true);
current.insert(segment, toml_edit::Item::Table(table));
}
PathLookup::Existing => return Ok(None),
}
}
let item = current
.get_mut(segment)
.expect("segment exists or was inserted above");
match item.as_table_like_mut() {
Some(table) => current = table,
None => match lookup {
PathLookup::Create => bail!("`{segment}` in config.toml must be a table"),
PathLookup::Existing => return Ok(None),
},
}
}
Ok(Some(current))
}
#[cfg(test)]
mod tests {
#[test]
fn healing_lifts_nested_extras_towers_to_the_top_level() {
let tmp = tempfile::tempdir().expect("tempdir");
let path = tmp.path().join("config.toml");
std::fs::write(
&path,
concat!(
"reasoning_effort = \"high\"\n\n",
"[projects.\"/live\"]\n",View on GitHub (pinned to 0c42157ee5)
Solutions
- Edit config.toml and convert the named scalar into a table, moving the old value under an appropriate key inside it
- Remove the stale key entirely and let Codewhale write the nested structure fresh
- After upgrading Codewhale, run any provided config migration/doctor command before setting nested options
Example fix
# before (config.toml) model = "gpt-4o" # after (config.toml) [model] name = "gpt-4o" # or simply remove the line and re-apply settings
Defensive patterns
Strategy: type-guard
Validate before calling
// Before setting a nested value, ensure every prefix segment is table-like:
fn path_segments_are_tables(doc: &toml_edit::DocumentMut, segments: &[&str]) -> bool {
let mut cur = doc.as_table();
for seg in segments {
match cur.get(*seg) {
None | Some(toml_edit::Item::Table(_)) => return true, // creatable
Some(item) if item.is_table_like() => { /* descend */ }
_ => return false, // scalar/array blocks Create
}
}
true
} Type guard
fn is_table_like(item: &toml_edit::Item) -> bool {
item.as_table_like().is_some()
} Try / catch
match set_config_document_value(&mut doc, segments, value) {
Ok(Some(_)) => { /* applied */ }
Ok(None) | Err(_) if seg_conflicts(config_text, segments) => {
// show the offending scalar and offer migration to [table] form
}
Err(e) => return Err(e),
} Prevention
- After upgrades, lint config.toml for scalar keys that the new schema expects as tables
- Prefer fully-qualified nested keys when writing config programmatically
- Back up config.toml before schema-migrating versions
When it happens
Trigger: Code sets a nested value like `model.provider = "acme"` while config.toml already contains a scalar at the same key, e.g. `model = "gpt-4o"` at top level; the descent hits a non-table item and bails instead of overwriting user data.
Common situations: Config schema drift after upgrading Codewhale (a key that used to be a string is now a table); hand-written minimal configs that set `model = "..."`; leftover keys from an older config format colliding with new nested settings.
Related errors
- failed to parse config at {}; file contents were omitted
- key not found: {key}
- provider auth source command must include at least one non-e
- provider auth source secret must include secret_id
- context_window must be greater than 0
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/b967a6f2ee766922.
Report an issue: GitHub.