affaan-m/ECC · error

Refusing to remove Claude hook for event

Error message

Refusing to remove Claude hook for event "${event}" and id "${previousEntry.id}" because the previous managed entry has drifted

What it means

During mergeManagedHooks removal of stale managed hooks, if a previously recorded managed hook entry exists in settings but its contents no longer deep-equal the recorded previous entry, the merge refuses to remove it. This protects hand-modified or externally changed hooks from being silently deleted. Repair mode and exact matches proceed with removal.

Solutions

  1. Revert your manual edits to that hook entry so it matches the previously installed version, then rerun.
  2. Run the operation in repair mode (mode: 'repair' or repair: true) if you intentionally want the drifted hook replaced/removed.
  3. Manually delete the drifted hook from settings.json if you no longer want it, then rerun the merge.
  4. Back up settings.json before using repair mode so local customizations can be recovered.

Example fix

// before
await mergeManagedHooks({ settings, desiredHooks, previousManagedHooks });
// after (explicitly allow replacing drifted entries)
await mergeManagedHooks({ settings, desiredHooks, previousManagedHooks, mode: 'repair' });
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await mergeManagedHooks({ settings, desiredHooks, previousManagedHooks });
} catch (error) {
  if (error.message.includes('previous managed entry has drifted')) {
    // ask user or run repair deliberately
    await mergeManagedHooks({ settings, desiredHooks, previousManagedHooks, mode: 'repair' });
  } else throw error;
}

Prevention

When it happens

Trigger: Running an uninstall/merge where previousManagedHooks records a hook that the user (or another tool) has since edited in settings.json; the recorded id still matches but the entry object has drifted.

Common situations: A user customized command strings, matchers, or timeouts of an ECC-managed hook in settings.json, then ran the installer which wanted to remove or replace the stale hook.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/0ea627e1c111d566. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/install/claude-settings.js:505

  }

  let nextHooks = validatedSettings.hooks
    ? cloneValue(validatedSettings.hooks)
    : {};
  const added = [];
  const updated = [];
  const unchanged = [];
  const removed = [];

  if (previousHooks) {
    for (const [event, previousEntries] of Object.entries(previousHooks)) {
      let eventEntries = nextHooks[event] ? cloneValue(nextHooks[event]) : [];
      for (const previousEntry of previousEntries) {
        if (managedEntryFor(desiredHooks, event, previousEntry.id)) continue;
        const match = assertUnambiguousMatch(eventEntries, event, previousEntry.id);
        if (!match) continue;
        if (!isDeepStrictEqual(match.entry, previousEntry)) {
          throw new Error(
            `Refusing to remove Claude hook for event "${event}" and id `
            + `"${previousEntry.id}" because the previous managed entry has drifted`
          );
        }
        eventEntries = eventEntries.filter((_entry, index) => index !== match.index);
        removed.push(reference(event, previousEntry.id));
      }
      nextHooks = eventEntries.length > 0
        ? { ...nextHooks, [event]: eventEntries }
        : withoutProperty(nextHooks, event);
    }
  }

  for (const [event, desiredEntries] of Object.entries(desiredHooks)) {
    let eventEntries = nextHooks[event] ? cloneValue(nextHooks[event]) : [];
    for (const desiredEntry of desiredEntries) {
      const match = assertUnambiguousMatch(eventEntries, event, desiredEntry.id);
      if (!match) {

View on GitHub (pinned to 8321021c54)