{"record":{"id":"1400b6af94b29b7c","repo":"Kuberwastaken/claurst","slug":"hooks-event-name-must-be-an-object","errorCode":null,"errorMessage":"hooks.{event_name}[] must be an object","messagePattern":"hooks\\.(.+?)\\[\\] must be an object","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-rust/crates/core/src/import_config.rs","lineNumber":720,"sourceCode":"\n    Ok(servers)\n}\n\nfn parse_hooks(value: &Value) -> Result<HashMap<HookEvent, Vec<HookEntry>>> {\n    let Some(obj) = value.as_object() else {\n        return Err(anyhow!(\"hooks must be an object\"));\n    };\n    let mut out = HashMap::new();\n    for (event_name, event_value) in obj {\n        let event = parse_hook_event(event_name)?;\n        let entries = event_value\n            .as_array()\n            .ok_or_else(|| anyhow!(\"hooks.{event_name} must be an array\"))?;\n        let mut hook_entries = Vec::new();\n        for entry in entries {\n            let entry_obj = entry\n                .as_object()\n                .ok_or_else(|| anyhow!(\"hooks.{event_name}[] must be an object\"))?;\n            let matcher = entry_obj\n                .get(\"matcher\")\n                .and_then(Value::as_str)\n                .unwrap_or(\"*\")\n                .to_string();\n            let hooks = entry_obj\n                .get(\"hooks\")\n                .and_then(Value::as_array)\n                .ok_or_else(|| anyhow!(\"hooks.{event_name}[].hooks must be an array\"))?;\n            for hook in hooks {\n                let hook_obj = hook\n                    .as_object()\n                    .ok_or_else(|| anyhow!(\"hooks.{event_name}[].hooks[] must be an object\"))?;\n                let command = hook_obj\n                    .get(\"command\")\n                    .and_then(Value::as_str)\n                    .ok_or_else(|| anyhow!(\"hooks.{event_name} hook is missing command\"))?\n                    .to_string();","sourceCodeStart":702,"sourceCodeEnd":738,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/core/src/import_config.rs#L702-L738","documentation":"In parse_hooks, every element of an event's array must be a hook-group JSON object with optional \"matcher\" and required \"hooks\". A non-object element (string, null, number) in the array raises this error naming the event.","triggerScenarios":"Importing config where the event array contains raw strings or nulls, e.g. \"hooks\": {\"PreToolUse\": [\"npx lint\"]} or [null].","commonSituations":"Copy-pasted hooks where entries lost their object wrapping, JSON edited by scripts that pushed plain strings, or an intentionally disabled hook left as null.","solutions":["Convert each array element into an object with a \"hooks\" array of {\"command\": ...} entries","Remove non-object elements from the event array","Keep the documented shape: event -> [ { matcher, hooks: [ { command } ] } ]"],"exampleFix":"// before\n{ \"hooks\": { \"PreToolUse\": [\"npx lint\"] } }\n// after\n{ \"hooks\": { \"PreToolUse\": [ { \"matcher\": \"*\", \"hooks\": [ { \"command\": \"npx lint\" } ] } ] } }","handlingStrategy":"type-guard","validationCode":"for (const groups of Object.values(cfg.hooks ?? {})) {\n  for (const g of groups) if (typeof g !== 'object' || g === null || Array.isArray(g)) throw new Error('hook group entries must be objects');\n}","typeGuard":"const isHookGroup = (g) => typeof g === 'object' && g !== null && !Array.isArray(g) && Array.isArray(g.hooks);","tryCatchPattern":"try { importConfig(path) } catch (e) { if (/hooks\\.\\S+\\[\\] must be an object/.test(String(e))) { console.error('Wrap each hook entry in an object with matcher/hooks'); } else { throw e; } }","preventionTips":["Never place raw command strings directly in the event array","Every event array element must be an object with a hooks array","Lint the settings file for hook shape after manual edits"],"tags":["json","config-import","validation","hooks"],"backgroundTag":"config-type-mismatch","analyzedSha":"b0637c97ec34144387cbf2f74f65df6d16a6cef1","analyzedAt":"2026-09-10T00:24:58.650Z","contentChangedAt":"2026-09-10T00:24:58.650Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}