{"record":{"id":"84c213292c6e8269","repo":"affaan-m/ECC","slug":"invalid-managed-hook-entry-at-label-event-index-expected","errorCode":null,"errorMessage":"Invalid managed hook entry at ${label}.${event}[${index}]: expected hooks","messagePattern":"Invalid managed hook entry at (.+?)\\.(.+?)\\[(.+?)\\]: expected hooks","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/install/claude-settings.js","lineNumber":181,"sourceCode":"      if (\n        !Object.prototype.hasOwnProperty.call(entry, 'matcher')\n        && !EVENTS_WITHOUT_MATCHER.has(event)\n      ) {\n        throw new Error(\n          `Invalid managed hook entry at ${label}.${event}[${index}]: missing matcher`\n        );\n      }\n      if (\n        Object.prototype.hasOwnProperty.call(entry, 'matcher')\n        && typeof entry.matcher !== 'string'\n        && !isJsonObject(entry.matcher)\n      ) {\n        throw new Error(\n          `Invalid managed hook entry at ${label}.${event}[${index}]: invalid matcher`\n        );\n      }\n      if (!Array.isArray(entry.hooks) || entry.hooks.length === 0) {\n        throw new Error(\n          `Invalid managed hook entry at ${label}.${event}[${index}]: expected hooks`\n        );\n      }\n      entry.hooks.forEach((hook, hookIndex) => {\n        validateHookHandler(hook, `${label}.${event}[${index}].hooks[${hookIndex}]`);\n      });\n    });\n  }\n\n  return cloneValue(managedHooks);\n}\n\nfunction validateRecordedManagedHooks(managedHooks, label = 'recorded managed hooks') {\n  if (!isJsonObject(managedHooks) || Object.keys(managedHooks).length === 0) {\n    throw new Error(`Invalid ${label}: expected a non-empty JSON object`);\n  }\n  for (const [event, entries] of Object.entries(managedHooks)) {\n    if (!isNonEmptyString(event) || !Array.isArray(entries) || entries.length === 0) {","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/install/claude-settings.js#L163-L199","documentation":"Every hook entry must have a hooks array containing at least one handler definition. validateManagedHooks throws this when entry.hooks is missing, not an array, or an empty array. The hooks array holds the actual handler objects (command/http/prompt/agent) that Claude Code executes.","triggerScenarios":"Passing { id: 'x', matcher: 'Bash' } with no hooks field; hooks: []; hooks: 'cmd' (a string instead of an array).","commonSituations":"Hand-writing an entry and forgetting the hooks wrapper; removing all handlers from an entry during cleanup; a template that emits a singular hook object instead of an array; copying Claude-native settings where a flat handler replaced the array.","solutions":["Ensure each entry has hooks: [ ... ] with at least one handler object, e.g. { type: 'command', command: 'npx lint' }.","Wrap a single handler object in an array.","Locate the offending entry via the index in the message.","If the handler was intentionally removed, delete the whole entry instead of leaving an empty hooks array."],"exampleFix":"// before\n{ id: 'lint', matcher: 'Bash', hooks: [] }\n// after\n{ id: 'lint', matcher: 'Bash', hooks: [{ type: 'command', command: 'npm run lint' }] }","handlingStrategy":"validation","validationCode":"for (const entries of Object.values(managedHooks)) {\n  entries.forEach((e, i) => {\n    if (!Array.isArray(e.hooks) || e.hooks.length === 0) {\n      throw new Error(`Entry ${i} (${e.id}) must have a non-empty hooks array`);\n    }\n  });\n}","typeGuard":"function allEntriesHaveHandlers(hooks) {\n  return Object.values(hooks).flat().every(e =>\n    e !== null && typeof e === 'object' && Array.isArray(e.hooks) && e.hooks.length > 0);\n}","tryCatchPattern":"try {\n  materializeManagedHooks(hooks);\n} catch (err) {\n  if (/expected hooks/.test(err.message)) {\n    console.error('Each entry needs hooks: [{ type: \"command\", command: \"...\" }] with at least one handler');\n  }\n  throw err;\n}","preventionTips":["Use an entry factory that requires a handler argument","Wrap single handlers in arrays: hooks: [handler]","Delete entries instead of emptying their hooks array","Validate handler arrays in CI for hook configs"],"tags":["validation","missing-field","hooks"],"backgroundTag":"empty-required-field","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}