affaan-m/ECC · error
Invalid . : expected at least one hook entry
Error message
Invalid ${label}.${event}: expected at least one hook entry What it means
Each event's entries array must contain at least one hook entry. validateManagedHooks throws this when an event key exists but maps to an empty array, because an empty event group would produce no hooks and indicates a stale or mis-merged configuration.
Solutions
- Remove the empty event key entirely if no hooks are needed for it (or pass hooks without that key).
- Re-add at least one valid hook entry under the event.
- If hooks were removed intentionally, run the uninstall/remove path instead of validating an empty group.
- Regenerate the managed hooks block via the install tooling.
Example fix
// before
const hooks = { PreToolUse: [] };
// after
const hooks = {}; // or add at least one entry: { PreToolUse: [{ id: 'fmt', matcher: 'Bash', hooks: [...] }] } Defensive patterns
Strategy: validation
Validate before calling
for (const [event, entries] of Object.entries(managedHooks)) {
if (Array.isArray(entries) && entries.length === 0) delete managedHooks[event];
} Type guard
function hasNonEmptyEventGroups(v) {
return v !== null && typeof v === 'object' && !Array.isArray(v)
&& Object.values(v).every(e => Array.isArray(e) && e.length > 0);
} Try / catch
try {
desiredHooks(hooks);
} catch (err) {
if (/expected at least one hook entry/.test(err.message)) {
const event = err.message.match(/\.(\w+):/)?.[1];
console.warn(`Event "${event}" has no entries — drop the key or add a hook`);
}
throw err;
} Prevention
- Delete event keys entirely when their last hook is removed
- Filter empty groups before passing the map: Object.fromEntries(entries.filter(([,v])=>v.length))
- In merge tooling, drop keys whose arrays end up empty
- Add a pre-validate step that prunes empty arrays
When it happens
Trigger: Passing { PostToolUse: [] } or { SessionEnd: [] } to managedHooks, desiredHooks, expectedHooks, or the other six public callers; deleting all entries under an event during a manual edit but leaving the key.
Common situations: Manually removing the last hook under an event in settings.json; a merge conflict resolution that kept the event key but discarded all entries; programmatic filtering that removed every entry for an event.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Invalid Claude hooks preference
- Invalid hook entry at
- INVALID_HOOK_MODE
- Invalid hooks config: expected a JSON object with a hooks…
- Invalid . : expected a non-empty hook array
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/39d2420733376928.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/claude-settings.js:144
function validateManagedHooks(managedHooks, label = 'managed hooks') {
if (!isJsonObject(managedHooks)) {
throw new Error(`Invalid ${label}: expected a JSON object`);
}
if (Object.keys(managedHooks).length === 0) {
throw new Error(`Invalid ${label}: expected at least one hook event`);
}
const seenIds = new Set();
for (const [event, entries] of Object.entries(managedHooks)) {
if (!VALID_EVENTS.has(event)) {
throw new Error(`Invalid ${label}: unsupported hook event "${event}"`);
}
if (!Array.isArray(entries)) {
throw new Error(`Invalid ${label}.${event}: expected an array`);
}
if (entries.length === 0) {
throw new Error(`Invalid ${label}.${event}: expected at least one hook entry`);
}
entries.forEach((entry, index) => {
if (!isJsonObject(entry)) {
throw new Error(
`Invalid managed hook entry at ${label}.${event}[${index}]: expected a JSON object`
);
}
if (typeof entry.id !== 'string' || entry.id.trim() === '') {
throw new Error(
`Invalid managed hook entry at ${label}.${event}[${index}]: `
+ 'expected a non-empty unique id'
);
}
if (seenIds.has(entry.id)) {
throw new Error(`Invalid ${label}: expected globally unique id "${entry.id}"`);
}
seenIds.add(entry.id);View on GitHub (pinned to 8321021c54)