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

  1. Remove one of the two flags — pass only --enable-hooks to consent to the hook runtime, or only --no-hooks to install without it.
  2. If flags come from a wrapper script or alias, inspect it (type ecc / cat the script) and remove the hard-coded flag.
  3. 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

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


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)