xai-org/grok-build · error

permission.{key} is not an array

Error message

permission.{key} is not an array

What it means

merge_permissions found permission.allow (or permission.deny, etc.) present but not as a TOML array, so rule strings cannot be appended/deduped. Only a missing key gets a fresh empty array; an existing non-array value errors out.

Source

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

            RuleAction::Ask => ask_rules.push(formatted),
        }
    }

    for (key, new_rules) in [
        ("allow", allow_rules),
        ("deny", deny_rules),
        ("ask", ask_rules),
    ] {
        if new_rules.is_empty() {
            continue;
        }

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

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

        for rule_str in new_rules {
            if !existing_set.contains(&rule_str) {
                existing.push(TomlValue::String(rule_str));
                count += 1;
            }
        }
    }

    Ok(count)
}

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Convert the value to an array: allow = ["bash", "read"].
  2. Remove the malformed key so merge_permissions creates a fresh array and merges rules.
  3. Ensure all rule entries are strings, not tables or scalars.

Example fix

// before (config.toml)
[permission]
allow = "bash"

// after
[permission]
allow = ["bash"]
Defensive patterns

Strategy: validation

Validate before calling

let root: toml::Value = toml::from_str(&std::fs::read_to_string(&path)?)?;
for key in ["allow", "deny"] {
    if let Some(v) = root.get("permission").and_then(|p| p.get(key)) {
        if !v.is_array() {
            anyhow::bail!("permission.{key} must be an array of strings");
        }
    }
}

Type guard

fn rule_is_string_array(v: &toml::Value) -> bool {
    v.as_array().map(|a| a.iter().all(|x| x.is_str())).unwrap_or(false)
}

Try / catch

if let Err(e) = apply_import(items, &path) {
    if e.to_string().contains("is not an array") {
        eprintln!("Wrap rule values in [ ... ], e.g. allow = [\"bash\"]");
    } else {
        return Err(e.into());
    }
}

Prevention

When it happens

Trigger: apply_items_to_config merges rules while permission.allow (or another action key) is set to a string, boolean, or table instead of an array of strings.

Common situations: Hand-edit produced allow = "bash" instead of allow = ["bash"]; an inline table was placed where the array belongs.

Related errors


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