affaan-m/ECC · error
Unknown hook consent decision
Error message
Unknown hook consent decision: ${hookConsent} What it means
withHookConsent() attaches a hook consent decision to an install plan. The decision must be one of the values in HOOK_CONSENT_DECISIONS (e.g. 'enabled', 'declined'); any other non-null string is rejected with this error. It protects the plan from carrying an unrecognized consent state.
Solutions
- Use an exact allowed decision string — check HOOK_CONSENT_DECISIONS in hook-consent.js and pass 'enabled' or 'declined' verbatim (lowercase).
- Normalize user/script input (toLowerCase, trim) before passing it to withHookConsent.
- Pass no argument (default null) when there is no consent decision yet and let assertHookConsentReady handle gating later.
- If upgrading, update your integration to the current decision vocabulary in the latest ECC version.
Example fix
// before withHookConsent(plan, 'Enable') // after withHookConsent(plan, 'enabled')
Defensive patterns
Strategy: type-guard
Validate before calling
const DECISIONS = ['enabled', 'declined'];
if (decision !== null && !DECISIONS.includes(decision)) {
throw new Error(`Consent decision must be one of ${DECISIONS.join('|')} or null`);
} Type guard
function isHookConsentDecision(v) {
return v === null || v === 'enabled' || v === 'declined';
} Try / catch
try {
const plan2 = withHookConsent(plan, decision);
} catch (err) {
if (err.message.startsWith('Unknown hook consent decision')) {
console.error(`Bad decision '${decision}'; use 'enabled' or 'declined'`);
process.exitCode = 1;
} else throw err;
} Prevention
- Import/reuse the module's HOOK_CONSENT_DECISIONS constant instead of hardcoding strings.
- Normalize CLI input with trim() and toLowerCase() before mapping to a decision.
- Keep decisions centralized in one config module for your tooling.
- Add a unit test asserting your wrapper only passes valid decision values.
When it happens
Trigger: Calling withHookConsent(plan, decision) programmatically with a misspelled decision like 'enable', 'Declined', 'yes', or a value from an older API version; reading the consent value from unparsed CLI input without normalizing it.
Common situations: Custom automation scripts building install plans; renaming/typoing the decision constant in downstream tooling; upgrading code across a version where the allowed decision values changed.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Refusing to disable modified Claude hooks in
- This install would enable ECC's automatic hook runtime…
- Another ECC process is updating Claude settings
- At least one guided harness must be selected
- ${blockingIssues.map(issue => issue.message).join('; ')}
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/f244c3aab02eae7b.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/hook-consent.js:165
}
: plan.statePreview.resolution,
}
: plan.statePreview;
return {
...plan,
operations,
statePreview: setStatePreviewHookConsent(statePreview, 'declined'),
selectedModuleIds: withoutHookRuntimeId(plan.selectedModuleIds),
excludedModuleIds: hadHookRuntimeModule && Array.isArray(plan.excludedModuleIds)
? [...new Set([...plan.excludedModuleIds, HOOK_RUNTIME_MODULE_ID])]
: plan.excludedModuleIds,
};
}
function withHookConsent(plan, hookConsent = null) {
if (hookConsent !== null && !HOOK_CONSENT_DECISIONS.includes(hookConsent)) {
throw new Error(`Unknown hook consent decision: ${hookConsent}`);
}
if (hookConsent === 'declined') {
return { ...stripHookRuntimeFromPlan(plan), hookConsent };
}
return {
...plan,
hookConsent,
statePreview: setStatePreviewHookConsent(plan.statePreview, hookConsent),
};
}
function assertHookConsentReady(plan = {}) {
if (!planMaterializesHookRuntime(plan)) {
return;
}
if (plan.hookConsent === 'enabled') {
return;
}View on GitHub (pinned to 8321021c54)