{"record":{"id":"196ea5ba458bc351","repo":"xai-org/grok-build","slug":"permission-is-not-a-table","errorCode":null,"errorMessage":"[permission] is not a table","messagePattern":"\\[permission\\] is not a table","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/claude_import.rs","lineNumber":859,"sourceCode":"    }\n\n    Ok(count)\n}\n\n/// Merge permission rules into `[permission]` using the compact format.\n///\n/// Existing rules are preserved. New rules are appended to the appropriate\n/// action list (`allow`, `deny`, `ask`).\nfn merge_permissions(\n    table: &mut TomlMap<String, TomlValue>,\n    rules: &[&PermissionRule],\n) -> anyhow::Result<usize> {\n    let permission = table\n        .entry(\"permission\")\n        .or_insert_with(|| TomlValue::Table(TomlMap::new()));\n    let perm_table = permission\n        .as_table_mut()\n        .ok_or_else(|| anyhow::anyhow!(\"[permission] is not a table\"))?;\n\n    let mut count = 0;\n\n    // Group rules by action.\n    let mut allow_rules: Vec<String> = Vec::new();\n    let mut deny_rules: Vec<String> = Vec::new();\n    let mut ask_rules: Vec<String> = Vec::new();\n\n    for rule in rules {\n        let formatted = format_rule_string(rule);\n        match rule.action {\n            RuleAction::Allow => allow_rules.push(formatted),\n            RuleAction::Deny => deny_rules.push(formatted),\n            RuleAction::Ask => ask_rules.push(formatted),\n        }\n    }\n\n    for (key, new_rules) in [","sourceCodeStart":841,"sourceCodeEnd":877,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/claude_import.rs#L841-L877","documentation":"merge_permissions found a permission key at the config root whose value is not a table, so allow/deny rule arrays cannot be merged under it. The function only creates the table when the key is absent.","triggerScenarios":"apply_items_to_config processes permission rules while the config has a non-table value bound to permission, e.g. permission = \"allow-all\".","commonSituations":"User wrote permission as a string/boolean instead of a [permission] section; a different tool claimed the key with a scalar value.","solutions":["Replace the scalar permission value with a proper [permission] section in the config.","Delete the permission key and re-run the import so the table is created.","Use an inline table: permission = { allow = [], deny = [] }."],"exampleFix":"// before (config.toml)\npermission = \"allow\"\n\n// after\n[permission]\nallow = [\"bash\"]\ndeny = []","handlingStrategy":"validation","validationCode":"let root: toml::Value = toml::from_str(&std::fs::read_to_string(&path)?)?;\nif let Some(v) = root.get(\"permission\") {\n    if !v.is_table() {\n        anyhow::bail!(\"permission must be a [permission] table\");\n    }\n}","typeGuard":"fn permission_is_table(root: &toml::Value) -> bool {\n    root.get(\"permission\").map(|v| v.is_table()).unwrap_or(true)\n}","tryCatchPattern":"if let Err(e) = apply_import(items, &path) {\n    if e.to_string().contains(\"[permission] is not a table\") {\n        eprintln!(\"Convert the permission key to a [permission] section, then retry\");\n    } else {\n        return Err(e.into());\n    }\n}","preventionTips":["Write permission rules only under a [permission] section.","Never assign a scalar/string to the permission key.","Let the importer create the section rather than hand-authoring it."],"tags":["toml","config","schema"],"backgroundTag":"invalid-toml-config","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}