xai-org/grok-build · error

[paths] is not a table

Error message

[paths] is not a table

What it means

merge_paths found a paths key whose value is not a table, so the per-key path arrays cannot be merged. Only a missing paths key is auto-created as an empty table; an existing non-table value fails instead of being overwritten.

Source

Thrown at crates/codegen/xai-grok-shell/src/claude_import.rs:1009

    }
    Ok(count)
}

/// Merge a list of path strings into `[paths] <key>` (an array of strings).
///
/// Existing entries are preserved; new entries that aren't already present
/// are appended. Returns the number of newly added entries.
fn merge_paths(
    table: &mut TomlMap<String, TomlValue>,
    key: &str,
    new_paths: &[&str],
) -> anyhow::Result<usize> {
    let paths = table
        .entry("paths")
        .or_insert_with(|| TomlValue::Table(TomlMap::new()));
    let paths_table = paths
        .as_table_mut()
        .ok_or_else(|| anyhow::anyhow!("[paths] is not a table"))?;

    let arr = paths_table
        .entry(key)
        .or_insert_with(|| TomlValue::Array(Vec::new()));
    let existing = arr
        .as_array_mut()
        .ok_or_else(|| anyhow::anyhow!("paths.{key} is not an array"))?;

    let existing_set: std::collections::HashSet<String> = existing
        .iter()
        .filter_map(|v| v.as_str().map(|s| s.to_string()))
        .collect();

    let mut count = 0usize;
    for p in new_paths {
        if !existing_set.contains(*p) {
            existing.push(TomlValue::String(p.to_string()));
            count += 1;

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Replace the scalar with a [paths] section whose values are arrays of strings.
  2. Delete the malformed paths key and re-run the import so the table is created.
  3. Use an inline table: paths = { include = [], exclude = [] }.

Example fix

// before (config.toml)
paths = "/home/user/project"

// after
[paths]
include = ["/home/user/project"]
Defensive patterns

Strategy: validation

Validate before calling

let root: toml::Value = toml::from_str(&std::fs::read_to_string(&path)?)?;
if let Some(v) = root.get("paths") {
    if !v.is_table() {
        anyhow::bail!("paths must be a [paths] table of arrays");
    }
}

Type guard

fn paths_is_table(root: &toml::Value) -> bool {
    root.get("paths").map(|v| v.is_table()).unwrap_or(true)
}

Try / catch

if let Err(e) = apply_import(items, &path) {
    if e.to_string().contains("[paths] is not a table") {
        eprintln!("Convert paths to a [paths] section with array values, then retry");
    } else {
        return Err(e.into());
    }
}

Prevention

When it happens

Trigger: apply_items_to_config merges path entries while the config has a non-table value at the root key paths, e.g. paths = "/some/dir".

Common situations: User set paths to a single string instead of a [paths] section; an earlier tool stored a scalar under paths.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/b9848192895a7edf. Report an issue: GitHub.