affaan-m/ECC · error

Invalid hook entry at

Error message

Invalid hook entry at ${label}.${event}[${index}]

What it means

Each entry inside a hook event array must be a JSON object with a non-empty string "id" and an array "hooks". The validator walks every entry by index and throws this error at the first entry violating that shape. It guarantees recorded hook entries can be safely merged into settings without undefined fields downstream.

Solutions

  1. Open the recorded hooks data and fix the entry at the reported index so it has a non-empty string id and an array hooks field
  2. Wrap bare hook commands in the expected { id, hooks: [...] } shape
  3. Regenerate the recording from the canonical hooks.json
  4. Add a pre-validation pass on your own data to reject entries lacking id/hooks before calling the library

Example fix

// before
{ "hooks": { "type": "command", "command": "node hook.js" } }
// after
{ "id": "format-on-edit", "hooks": [ { "type": "command", "command": "node hook.js" } ] }
Defensive patterns

Strategy: validation

Validate before calling

const validEntry = (e) => e && typeof e === 'object' && typeof e.id === 'string' && e.id.length > 0 && Array.isArray(e.hooks);

Type guard

const isHookEntry = (v) => typeof v === 'object' && v !== null && typeof v.id === 'string' && Array.isArray(v.hooks);

Try / catch

try { validateRecordedManagedHooks(hooks); } catch (e) { const m = /hook entry at (.+)\[(\d+)\]/.exec(e.message); if (m) { console.error('Bad entry:', m[1], 'index', m[2]); } throw e; }

Prevention

When it happens

Trigger: Calling validateRecordedManagedHooks (or validate/previousHooks/recordedHooks) where managedHooks[event][index] is not an object, has a missing/empty/non-string id, or has a missing or non-array hooks field.

Common situations: Hand-edited hooks.json entries where "id" was renamed or removed, YAML-to-JSON conversion dropped fields, or a script appended a bare hook command object instead of the wrapper { id, hooks } structure.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

      });
    });
  }

  return cloneValue(managedHooks);
}

function validateRecordedManagedHooks(managedHooks, label = 'recorded managed hooks') {
  if (!isJsonObject(managedHooks) || Object.keys(managedHooks).length === 0) {
    throw new Error(`Invalid ${label}: expected a non-empty JSON object`);
  }
  for (const [event, entries] of Object.entries(managedHooks)) {
    if (!isNonEmptyString(event) || !Array.isArray(entries) || entries.length === 0) {
      throw new Error(`Invalid ${label}.${event}: expected a non-empty hook array`);
    }
    const seenIds = new Set();
    entries.forEach((entry, index) => {
      if (!isJsonObject(entry) || !isNonEmptyString(entry.id) || !Array.isArray(entry.hooks)) {
        throw new Error(`Invalid hook entry at ${label}.${event}[${index}]`);
      }
      if (seenIds.has(entry.id)) {
        throw new Error(
          `Invalid ${label}: expected unique id "${entry.id}" within event "${event}"`
        );
      }
      seenIds.add(entry.id);
    });
  }
  return cloneValue(managedHooks);
}

function validateSettings(settings, label = 'Claude settings') {
  if (!isJsonObject(settings)) {
    throw new Error(`Invalid ${label}: expected a JSON object`);
  }

  if (Object.prototype.hasOwnProperty.call(settings, 'hooks')) {

View on GitHub (pinned to 8321021c54)