affaan-m/ECC · error
Invalid managed hook entry at
Error message
Invalid managed hook entry at ${label}.${event}[${index}]: expected a JSON object What it means
Each hook entry inside an event array must be a plain JSON object. validateManagedHooks throws this when an entry is a string, number, array, null, or a non-plain object (e.g. a class instance whose prototype is not Object.prototype). Entries must carry the structured fields (id, matcher, hooks) this library manages.
Solutions
- Replace each non-object entry with a full hook-entry object: { id, matcher, hooks: [...] }.
- Check the index in the message (label.event[index]) to locate the offending element.
- If passing programmatically-created objects, ensure they are plain object literals (Object.getPrototypeOf(v) === Object.prototype || null).
- Regenerate the entries via the ECC install tooling.
Example fix
// before
const hooks = { PreToolUse: ['npx fmt'] };
// after
const hooks = { PreToolUse: [{ id: 'fmt', matcher: 'Bash', hooks: [{ type: 'command', command: 'npx fmt' }] }] }; Defensive patterns
Strategy: type-guard
Validate before calling
managedHooks && Object.values(managedHooks).flat().forEach((e, i) => {
if (e === null || typeof e !== 'object' || Array.isArray(e)) {
throw new Error(`Entry ${i} is not a plain object`);
}
}); Type guard
function isPlainObject(v) {
return v !== null && typeof v === 'object' && !Array.isArray(v)
&& (Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
} Try / catch
try {
managedHooks(hooks);
} catch (err) {
if (/expected a JSON object/.test(err.message)) {
console.error('A hook entry is not a plain object — use { id, matcher, hooks: [...] }');
}
throw err;
} Prevention
- Never use shorthand strings for hook entries
- Use JSON.parse/JSON.stringify round-trip to normalize to plain objects
- Avoid class instances and Maps in config values
- Validate every element with isPlainObject before calling the API
When it happens
Trigger: Passing an event array whose elements are raw command strings like { PreToolUse: ['fmt.sh'] }, a null element, or an object created with a custom class/prototype.
Common situations: Condensing entries to shorthand strings when hand-editing; spreading an array into the wrong position; using JSON parsed with a reviver that returns class instances; passing a Map instead of a plain object.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Invalid . : expected an array
- Invalid managed hook entry at
- Invalid managed hook handler at
- Canonical session snapshot must be an object
- Canonical session snapshot requires
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/054a932b80f122b7.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/claude-settings.js:149
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);
if (
!Object.prototype.hasOwnProperty.call(entry, 'matcher')
&& !EVENTS_WITHOUT_MATCHER.has(event)
) {
throw new Error(View on GitHub (pinned to 8321021c54)