affaan-m/ECC · error
Invalid managed hook handler at
Error message
Invalid managed hook handler at ${label}: async requires command type What it means
The 'async' flag is only meaningful for hooks of type 'command'. validateHookHandler throws this error when a hook of any other type (http, prompt, agent) defines hook.async. Remove async or switch the hook to type 'command'.
Solutions
- Delete the async property from non-command hook handlers.
- If the hook genuinely needs async semantics, change its type to 'command' and supply a valid command field.
- Update any shared templates or generators so async is only emitted for command-type hooks.
- Re-run validation after the edit to surface any remaining handler errors.
Example fix
// before
{ "type": "prompt", "prompt": "Review the diff", "async": true }
// after
{ "type": "prompt", "prompt": "Review the diff" } Defensive patterns
Strategy: validation
Validate before calling
const bad = hooks.filter(h=>h.type!=='command'&&'async' in h); if (bad.length) throw new Error('async only allowed on command hooks'); Type guard
const asyncAllowed = (h) => h.type === 'command' || h.async === undefined;
Try / catch
try { installHooks(cfg); } catch (e) { if (e.message.includes('async requires command type')) { console.error('Remove async from non-command hook:', e.message); process.exitCode = 1; } else throw e; } Prevention
- Only emit async in command-hook templates.
- Strip unknown fields when converting hooks between types.
- Document type-specific fields per hook type.
When it happens
Trigger: validateManagedHooks encounters {type:'http', url:'...', async:true}, {type:'prompt', prompt:'...', async:false}, or any non-command handler carrying an async key.
Common situations: Copying the async property from a command hook when converting it to an http/prompt hook; a shared hook template that always injects async; schema drift after the library tightened validation in a newer version.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Invalid hook entry at
- Invalid hooks config: expected a JSON object with a hooks…
- Invalid . : expected a non-empty hook array
- Invalid : expected at least one hook event
- Invalid managed hook handler at
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/0e36834739303a99.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/claude-settings.js:97
throw new Error(`Invalid managed hook handler at ${label}: invalid timeout`);
}
if (hook.type === 'command') {
const validCommand = isNonEmptyString(hook.command)
|| (Array.isArray(hook.command)
&& hook.command.length > 0
&& hook.command.every(isNonEmptyString));
if (!validCommand) {
throw new Error(`Invalid managed hook handler at ${label}: invalid command`);
}
if (hook.async !== undefined && typeof hook.async !== 'boolean') {
throw new Error(`Invalid managed hook handler at ${label}: invalid async flag`);
}
return;
}
if (hook.async !== undefined) {
throw new Error(`Invalid managed hook handler at ${label}: async requires command type`);
}
if (hook.type === 'http') {
if (!isNonEmptyString(hook.url)) {
throw new Error(`Invalid managed hook handler at ${label}: invalid url`);
}
if (
hook.headers !== undefined
&& (!isJsonObject(hook.headers)
|| !Object.values(hook.headers).every(value => typeof value === 'string'))
) {
throw new Error(`Invalid managed hook handler at ${label}: invalid headers`);
}
if (
hook.allowedEnvVars !== undefined
&& (!Array.isArray(hook.allowedEnvVars)
|| !hook.allowedEnvVars.every(isNonEmptyString))
) {
throw new Error(`Invalid managed hook handler at ${label}: invalid allowedEnvVars`);View on GitHub (pinned to 8321021c54)