affaan-m/ECC · error
--enable-hooks and --no-hooks are mutually exclusive
Error message
--enable-hooks and --no-hooks are mutually exclusive
What it means
resolveHookConsentFlags() maps CLI hook flags to a single consent decision. Passing both --enable-hooks and --no-hooks is contradictory (enable vs decline the hook runtime), so the function throws immediately before any install work happens.
Solutions
- Remove one of the two flags — pass only --enable-hooks to consent to the hook runtime, or only --no-hooks to install without it.
- If flags come from a wrapper script or alias, inspect it (type ecc / cat the script) and remove the hard-coded flag.
- Omit both flags to be prompted interactively via the guided installer (ecc install --guided).
Example fix
// before ecc install --enable-hooks --no-hooks // after ecc install --enable-hooks
Defensive patterns
Strategy: validation
Validate before calling
const flags = process.argv.slice(2);
if (flags.includes('--enable-hooks') && flags.includes('--no-hooks')) {
throw new Error('Pass either --enable-hooks or --no-hooks, not both');
} Try / catch
try {
const decision = resolveHookConsentFlags({ enableHooks, noHooks });
} catch (err) {
if (/mutually exclusive/.test(err.message)) {
console.error('Choose one: --enable-hooks (install hooks) or --no-hooks (skip them).');
process.exitCode = 1;
} else throw err;
} Prevention
- Do not hard-code hook flags in shared scripts/aliases; let users pass them explicitly.
- Build flag handling from a single options object so duplicates are visible.
- Prefer the guided installer when the choice is interactive.
- Lint CI commands for conflicting installer flags.
When it happens
Trigger: Invoking the installer with both flags on one command line, e.g. `ecc install --enable-hooks --no-hooks`; a wrapper script or npm script that appends one flag unconditionally while the user passes the other.
Common situations: Shell aliases or CI scripts with baked-in flags colliding with manual flags; copy-pasting two example commands into one; a teammate's documented command containing --no-hooks while the user adds --enable-hooks to opt in.
Understand the failure class
Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.
Related errors
- Choose only one output format: --json or --markdown
- INVALID_HOOK_MODE
- Invalid --hooks value
- --legacy-codex-sync cannot be combined with --target
- --no-hooks cannot be combined with an explicit…
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/9135e2a95fb66133.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install/hook-consent.js:81
|| destination.endsWith('/.cursor/hooks.json')
|| destination.includes('/.cursor/hooks/')
);
}
function planMaterializesHookRuntime(plan = {}) {
const operations = Array.isArray(plan.operations) ? plan.operations : [];
return operations.some(isHookRuntimeOperation);
}
function formatHookCapabilityDisclosure(indent = ' ') {
return HOOK_CAPABILITY_GROUPS
.map((group, index) => `${indent}${index + 1}. ${group.description}`)
.join('\n');
}
function resolveHookConsentFlags({ enableHooks = false, noHooks = false } = {}) {
if (enableHooks && noHooks) {
throw new Error('--enable-hooks and --no-hooks are mutually exclusive');
}
if (enableHooks) {
return 'enabled';
}
if (noHooks) {
return 'declined';
}
return null;
}
function withoutHookRuntimeId(values) {
return (Array.isArray(values) ? values : []).filter(value => value !== HOOK_RUNTIME_MODULE_ID);
}
function setStatePreviewHookConsent(statePreview, hookConsent) {
if (!statePreview || !statePreview.request) {
return statePreview;
}View on GitHub (pinned to 8321021c54)