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
- Replace the scalar with a [paths] section whose values are arrays of strings.
- Delete the malformed paths key and re-run the import so the table is created.
- 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
- Store path lists as arrays under a [paths] section, never as a single string.
- Validate paths.* values are tables of arrays before importing.
- Let the importer create the section instead of hand-writing it.
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
- config root is not a table
- [claude_compat] is not a table
- [permission] is not a table
- permission.{key} is not an array
- [mcp_servers] is not a table
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/b9848192895a7edf.
Report an issue: GitHub.