affaan-m/ECC · error
Invalid . : expected a non-empty hook array
Error message
Invalid ${label}.${event}: expected a non-empty hook array What it means
This library validates recorded managed hook definitions before writing them into Claude settings. Each hook event key must map to a non-empty array of hook entries. When an event's value is missing, not an array, or an empty array, this error is thrown so malformed hook recordings are rejected early instead of producing broken settings files.
Solutions
- Inspect the recorded hooks object and ensure every event key maps to a non-empty array of hook entries
- If an event legitimately has no hooks, remove the event key entirely instead of leaving an empty array
- Regenerate the hooks recording from the source hooks.json rather than hand-editing the recorded settings
- If loading from JSON, log/inspect the parsed object and fix the offending event key
Example fix
// before
{ "PreToolUse": [] }
// after
{ "PreToolUse": [ { "id": "pre-compact-suggest", "hooks": [ { "type": "command", "command": "node hook.js" } ] } ] } Defensive patterns
Strategy: validation
Validate before calling
function isValidRecordedHooks(h) { return !!h && typeof h === 'object' && !Array.isArray(h) && Object.entries(h).every(([k, v]) => typeof k === 'string' && Array.isArray(v) && v.length > 0); } Type guard
const isJsonObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
Try / catch
try { validateRecordedManagedHooks(hooks); } catch (e) { if (String(e.message).includes('non-empty hook array')) { /* drop empty event keys and retry */ } else throw e; } Prevention
- Never write empty arrays for hook events; omit the key instead
- Validate hooks.json schema in CI before publishing
- Regenerate recordings from source rather than hand-editing
- Keep hook entries in a typed structure to catch shape drift early
When it happens
Trigger: Calling validateRecordedManagedHooks (directly or via validate/findPreviousManagedHooks/previousHooks/recordedHooks) with a managedHooks object where some event key (e.g. "PreToolUse") maps to null, a non-array value, or an empty array [].
Common situations: A hooks.json was edited by hand and a hook block's matcher entries were deleted, a build script serialized an empty hooks list after filtering, or an older plugin version recorded hooks in a shape the current validator no longer accepts.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid hook entry at
- Invalid hooks config: expected a JSON object with a hooks…
- Invalid : expected at least one hook event
- Invalid managed hook handler at
- Invalid managed hook handler at
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/56ac36a9fcb89951.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/claude-settings.js:200
`Invalid managed hook entry at ${label}.${event}[${index}]: expected hooks`
);
}
entry.hooks.forEach((hook, hookIndex) => {
validateHookHandler(hook, `${label}.${event}[${index}].hooks[${hookIndex}]`);
});
});
}
return cloneValue(managedHooks);
}
function validateRecordedManagedHooks(managedHooks, label = 'recorded managed hooks') {
if (!isJsonObject(managedHooks) || Object.keys(managedHooks).length === 0) {
throw new Error(`Invalid ${label}: expected a non-empty JSON object`);
}
for (const [event, entries] of Object.entries(managedHooks)) {
if (!isNonEmptyString(event) || !Array.isArray(entries) || entries.length === 0) {
throw new Error(`Invalid ${label}.${event}: expected a non-empty hook array`);
}
const seenIds = new Set();
entries.forEach((entry, index) => {
if (!isJsonObject(entry) || !isNonEmptyString(entry.id) || !Array.isArray(entry.hooks)) {
throw new Error(`Invalid hook entry at ${label}.${event}[${index}]`);
}
if (seenIds.has(entry.id)) {
throw new Error(
`Invalid ${label}: expected unique id "${entry.id}" within event "${event}"`
);
}
seenIds.add(entry.id);
});
}
return cloneValue(managedHooks);
}
function validateSettings(settings, label = 'Claude settings') {View on GitHub (pinned to 8321021c54)