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

  1. Edit config.toml and convert the named scalar into a table, moving the old value under an appropriate key inside it
  2. Remove the stale key entirely and let Codewhale write the nested structure fresh
  3. 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

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


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/b967a6f2ee766922. Report an issue: GitHub.