{"record":{"id":"7e76d568cfab4797","repo":"affaan-m/ECC","slug":"invalid-label-unsupported-hook-event-event","errorCode":null,"errorMessage":"Invalid ${label}: unsupported hook event \"${event}\"","messagePattern":"Invalid (.+?): unsupported hook event \"(.+?)\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/install/claude-settings.js","lineNumber":138,"sourceCode":"    throw new Error(`Invalid managed hook handler at ${label}: invalid prompt`);\n  }\n  if (hook.model !== undefined && !isNonEmptyString(hook.model)) {\n    throw new Error(`Invalid managed hook handler at ${label}: invalid model`);\n  }\n}\n\nfunction validateManagedHooks(managedHooks, label = 'managed hooks') {\n  if (!isJsonObject(managedHooks)) {\n    throw new Error(`Invalid ${label}: expected a JSON object`);\n  }\n  if (Object.keys(managedHooks).length === 0) {\n    throw new Error(`Invalid ${label}: expected at least one hook event`);\n  }\n\n  const seenIds = new Set();\n  for (const [event, entries] of Object.entries(managedHooks)) {\n    if (!VALID_EVENTS.has(event)) {\n      throw new Error(`Invalid ${label}: unsupported hook event \"${event}\"`);\n    }\n    if (!Array.isArray(entries)) {\n      throw new Error(`Invalid ${label}.${event}: expected an array`);\n    }\n    if (entries.length === 0) {\n      throw new Error(`Invalid ${label}.${event}: expected at least one hook entry`);\n    }\n\n    entries.forEach((entry, index) => {\n      if (!isJsonObject(entry)) {\n        throw new Error(\n          `Invalid managed hook entry at ${label}.${event}[${index}]: expected a JSON object`\n        );\n      }\n      if (typeof entry.id !== 'string' || entry.id.trim() === '') {\n        throw new Error(\n          `Invalid managed hook entry at ${label}.${event}[${index}]: `\n          + 'expected a non-empty unique id'","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/install/claude-settings.js#L120-L156","documentation":"validateManagedHooks rejects any top-level key of the managed hooks map that is not one of the known Claude hook event names (VALID_EVENTS, e.g. PreToolUse, PostToolUse, SessionStart). The thrown message embeds the offending key so the developer can see which event name was rejected. This guard ensures ECC only materializes hooks Claude Code actually recognizes, preventing silently-ignored or corrupt settings.json content.","triggerScenarios":"Calling any of managedHooks, previousManagedHooks, inspectManagedOperation, materializeManagedHooks, desiredHooks, or expectedHooks with a hooks map containing a misspelled or invented event key, e.g. { PostTool: [...] } or { preToolUse: [...] } (wrong casing).","commonSituations":"Typo in a hand-edited hooks definition; snake_case/camelCase event names instead of PascalCase; event names copied from another tool (e.g. VS Code or GitHub Actions event names); a Claude Code hook event renamed across versions while an old config lingers.","solutions":["Fix the event key to an exact PascalCase name from VALID_EVENTS (SessionStart, UserPromptSubmit, PreToolUse, PermissionRequest, PostToolUse, PostToolUseFailure, Notification, SubagentStart, Stop, SubagentStop, PreCompact, InstructionsLoaded, TeammateIdle, TaskCompleted, ConfigChange, WorktreeCreate, WorktreeRemove, SessionEnd).","Check the message's quoted \"${event}\" value and compare character-by-character against the valid list (watch casing and spacing).","Regenerate the hooks map via the ECC install tooling instead of hand-editing, then re-run the operation.","If a genuinely new event is needed, add it to VALID_EVENTS in scripts/lib/install/claude-settings.js."],"exampleFix":"// before\nconst managedHooks = { PostToolUseFailure2: [{ id: 'lint', matcher: '*', hooks: [...] }] };\n// after\nconst managedHooks = { PostToolUseFailure: [{ id: 'lint', matcher: '*', hooks: [...] }] };","handlingStrategy":"validation","validationCode":"const VALID = new Set(['SessionStart','UserPromptSubmit','PreToolUse','PermissionRequest','PostToolUse','PostToolUseFailure','Notification','SubagentStart','Stop','SubagentStop','PreCompact','InstructionsLoaded','TeammateIdle','TaskCompleted','ConfigChange','WorktreeCreate','WorktreeRemove','SessionEnd']);\nconst bad = Object.keys(managedHooks).filter(e => !VALID.has(e));\nif (bad.length) throw new Error(`Unknown hook events: ${bad.join(', ')}`);","typeGuard":"function hasOnlyValidEvents(hooks) {\n  return hooks !== null && typeof hooks === 'object' && !Array.isArray(hooks)\n    && Object.keys(hooks).every(e => VALID_EVENT_SET.has(e));\n}","tryCatchPattern":"try {\n  materializeManagedHooks(hooks);\n} catch (err) {\n  if (/unsupported hook event/.test(err.message)) {\n    const bad = err.message.match(/\"([^\"]+)\"/)?.[1];\n    console.error(`Fix event name \"${bad}\" — must be PascalCase Claude event (e.g. PreToolUse)`);\n  }\n  throw err;\n}","preventionTips":["Keep a shared constant of valid event names and build configs from it","Never hand-type event names — copy from VALID_EVENTS","Watch casing: events are PascalCase (PreToolUse, not preToolUse)","Lint hook configs against VALID_EVENTS in CI before install"],"tags":["validation","hooks","configuration"],"backgroundTag":"invalid-enum-value","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"}