{"record":{"id":"4f90823c595b1a81","repo":"xai-org/grok-build","slug":"paths-key-is-not-an-array","errorCode":null,"errorMessage":"paths.{key} is not an array","messagePattern":"paths\\.(.+?) is not an array","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/claude_import.rs","lineNumber":1016,"sourceCode":"/// are appended. Returns the number of newly added entries.\nfn merge_paths(\n    table: &mut TomlMap<String, TomlValue>,\n    key: &str,\n    new_paths: &[&str],\n) -> anyhow::Result<usize> {\n    let paths = table\n        .entry(\"paths\")\n        .or_insert_with(|| TomlValue::Table(TomlMap::new()));\n    let paths_table = paths\n        .as_table_mut()\n        .ok_or_else(|| anyhow::anyhow!(\"[paths] is not a table\"))?;\n\n    let arr = paths_table\n        .entry(key)\n        .or_insert_with(|| TomlValue::Array(Vec::new()));\n    let existing = arr\n        .as_array_mut()\n        .ok_or_else(|| anyhow::anyhow!(\"paths.{key} is not an array\"))?;\n\n    let existing_set: std::collections::HashSet<String> = existing\n        .iter()\n        .filter_map(|v| v.as_str().map(|s| s.to_string()))\n        .collect();\n\n    let mut count = 0usize;\n    for p in new_paths {\n        if !existing_set.contains(*p) {\n            existing.push(TomlValue::String(p.to_string()));\n            count += 1;\n        }\n    }\n    Ok(count)\n}\n\n/// Merge `Hook` items into `<hooks_dir>/imported-from-claude.json`.\n///","sourceCodeStart":998,"sourceCodeEnd":1034,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/claude_import.rs#L998-L1034","documentation":"merge_paths adds a PATHS key (e.g. env PATH-style path lists) to a TOML settings table. It inserts an empty array if the key is missing, then requires the existing value to be a TOML array; if the key already exists but holds a non-array value (string, table, etc.) it cannot be merged, so this error is thrown.","triggerScenarios":"apply_items_to_config / merge_paths is called on a settings.toml in which paths.<key> exists but was hand-edited to a string or inline table instead of an array of strings.","commonSituations":"Users editing Claude-style settings.toml by hand (e.g. paths.cfg = \"/usr/bin\" instead of paths.cfg = [\"/usr/bin\"]), or a schema change from older versions that stored paths as a single string.","solutions":["Open the settings.toml and change paths.<key> to an array of strings, e.g. paths.cfg = [\"/usr/bin\"]","Delete the offending paths.<key> line and re-run the import so it is recreated as an empty array","Validate the TOML with a schema check before running the import"],"exampleFix":"# before\n[paths]\ncfg = \"/usr/local/bin\"\n# after\n[paths]\ncfg = [\"/usr/local/bin\"]","handlingStrategy":"validation","validationCode":"// before calling the import\nlet v = settings.get(\"paths\").and_then(|p| p.get(key));\nif let Some(v) = v {\n    assert!(v.is_array(), \"paths.{key} must be an array of strings\");\n}","typeGuard":"fn is_string_array(v: &toml::Value) -> bool {\n    v.as_array().map_or(true, |a| a.iter().all(|x| x.is_str()))\n}","tryCatchPattern":"match merge_paths(&mut cfg, key, entries) {\n    Err(e) if e.to_string().contains(\"is not an array\") => {\n        // reset the key and retry once\n        cfg[\"paths\"][key] = toml::Value::Array(vec![]);\n        merge_paths(&mut cfg, key, entries)\n    }\n    r => r,\n}","preventionTips":["Never hand-edit paths entries to bare strings; always use arrays","Lint settings.toml with a schema before running imports","Back up settings files before import"],"tags":["toml","config","type-mismatch"],"backgroundTag":"toml-type-mismatch","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}