{"record":{"id":"4c6d10f04b9332a0","repo":"xai-org/grok-build","slug":"root-is-not-a-json-object","errorCode":null,"errorMessage":"{}: root is not a JSON object","messagePattern":"(.+?): root is not a JSON object","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/claude_import.rs","lineNumber":1069,"sourceCode":"    let target = hooks_dir.join(\"imported-from-claude.json\");\n\n    // Read existing JSON if present.\n    let mut root: serde_json::Value = match std::fs::read_to_string(&target) {\n        Ok(s) => serde_json::from_str(&s).unwrap_or_else(|e| {\n            warn!(\n                path = %target.display(),\n                error = %e,\n                \"Existing imported-from-claude.json is malformed; replacing with fresh content. \\\n                 Manual edits in the malformed file will be lost.\"\n            );\n            serde_json::json!({})\n        }),\n        Err(e) if e.kind() == std::io::ErrorKind::NotFound => serde_json::json!({}),\n        Err(e) => return Err(e.into()),\n    };\n    let root_obj = root\n        .as_object_mut()\n        .ok_or_else(|| anyhow::anyhow!(\"{}: root is not a JSON object\", target.display()))?;\n    let hooks_obj = root_obj\n        .entry(\"hooks\".to_string())\n        .or_insert_with(|| serde_json::json!({}))\n        .as_object_mut()\n        .ok_or_else(|| anyhow::anyhow!(\"{}: hooks is not a JSON object\", target.display()))?;\n\n    let mut count = 0usize;\n    // `dirty` tracks whether we mutated the JSON in any way (including\n    // in-place timeout refreshes that don't add new entries). The file is\n    // re-written iff dirty, even when count == 0.\n    let mut dirty = false;\n    for item in new_hooks {\n        let ImportableItem::Hook {\n            event,\n            matcher,\n            command,\n            timeout,\n        } = item","sourceCodeStart":1051,"sourceCodeEnd":1087,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/claude_import.rs#L1051-L1087","documentation":"apply_hooks_to_dir reads the target settings.json, falling back to an empty JSON object when the file is absent, then requires the parsed root to be a JSON object so 'hooks' can be inserted. If the file's top-level JSON value is an array, string, number, or null, the mutation cannot proceed and this error is thrown.","triggerScenarios":"Running apply_import when ~/.claude/settings.json (or the matched dir target) contains valid JSON whose top level is not an object, e.g. the file is '[]' or '\"settings\"'.","commonSituations":"Manually edited or corrupted settings.json; a tool that wrote a JSON array; an empty-but-invalid placeholder file; a truncated write from a crash.","solutions":["Inspect the target file and wrap the content in an object, e.g. {} or {\"hooks\": {}}","Back up and replace the malformed settings.json with an empty JSON object, then re-run the import","Fix whatever tool is writing a non-object root to settings.json"],"exampleFix":"// before (settings.json)\n[]\n// after\n{}","handlingStrategy":"validation","validationCode":"// pre-flight check\nlet raw = std::fs::read_to_string(path)?;\nlet v: serde_json::Value = serde_json::from_str(&raw)?;\nif !v.is_object() {\n    return Err(format!(\"{}: root is not an object\", path.display()).into());\n}","typeGuard":"fn is_json_object(v: &serde_json::Value) -> bool {\n    v.is_object()\n}","tryCatchPattern":"match apply_import(...) {\n    Err(e) if e.to_string().contains(\"root is not a JSON object\") => {\n        std::fs::copy(&target, \"settings.json.bak\")?;\n        std::fs::write(&target, \"{}\")?;\n        apply_import(...) // retry\n    }\n    r => r,\n}","preventionTips":["Validate settings.json is a JSON object before running imports","Avoid tools that write bare arrays/strings to settings.json","Keep a backup of settings.json to restore after corruption"],"tags":["json","config","schema"],"backgroundTag":"json-root-not-object","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}