affaan-m/ECC · error
Invalid : expected hooks. to be an array
Error message
Invalid ${label}: expected hooks.${event} to be an array What it means
Each value inside settings.hooks must be an array of hook entries. After confirming hooks is an object, the validator iterates its event keys and throws this error if any event's value is not an array. This keeps the hooks structure consistent with Claude's settings schema.
Solutions
- Wrap the event's hook entries in an array
- Remove the malformed event key if it holds no valid hooks
- Re-run validation after fixing to catch any other malformed events
- Compare against a known-good settings.json hooks block
Example fix
// before
"Stop": { "type": "command", "command": "x" }
// after
"Stop": [ { "type": "command", "command": "x" } ] Defensive patterns
Strategy: validation
Validate before calling
const allArrays = (hooks) => Object.values(hooks).every(Array.isArray);
Type guard
const isHookArray = (v) => Array.isArray(v);
Try / catch
try { return parseSettings(s); } catch (e) { const m = /hooks\.(\S+) to be an array/.exec(e.message); if (m) { console.error('Event', m[1], 'must be an array'); } throw e; } Prevention
- Always wrap hook entries in arrays, even single hooks
- Validate hooks blocks after any programmatic merge
- Lint hooks.json with a JSON schema
- Avoid flattening tools that rewrite hooks objects
When it happens
Trigger: Calling parseSettings/validatedSettings/validateSettings where settings.hooks[event] is a string, object, or number instead of an array — e.g. "hooks": { "Stop": { "command": ... } }.
Common situations: A user flattened a single hook into an object instead of wrapping it in an array, a merge tool replaced an array with a keyed object, or hand-editing removed the [ ] brackets around entries.
Related errors
- Invalid : expected "hooks" to be a JSON object
- Claude settings contains multiple hooks for event
- Invalid Claude hooks preference
- Invalid hook entry at
- INVALID_HOOK_MODE
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/842b0fcd0acd099e.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/claude-settings.js:229
}
seenIds.add(entry.id);
});
}
return cloneValue(managedHooks);
}
function validateSettings(settings, label = 'Claude settings') {
if (!isJsonObject(settings)) {
throw new Error(`Invalid ${label}: expected a JSON object`);
}
if (Object.prototype.hasOwnProperty.call(settings, 'hooks')) {
if (!isJsonObject(settings.hooks)) {
throw new Error(`Invalid ${label}: expected "hooks" to be a JSON object`);
}
for (const [event, entries] of Object.entries(settings.hooks)) {
if (!Array.isArray(entries)) {
throw new Error(`Invalid ${label}: expected hooks.${event} to be an array`);
}
}
}
return cloneValue(settings);
}
function replacePluginRootPlaceholders(value, pluginRoot) {
if (typeof pluginRoot !== 'string') {
throw new Error('Invalid Claude plugin root: expected a string');
}
if (typeof value === 'string') {
return value.split(PLUGIN_ROOT_PLACEHOLDER).join(pluginRoot);
}
if (Array.isArray(value)) {
return value.map(item => replacePluginRootPlaceholders(item, pluginRoot));
}
if (isJsonObject(value)) {View on GitHub (pinned to 8321021c54)