{"record":{"id":"198282ecbaeca829","repo":"affaan-m/ECC","slug":"invalid-managed-hook-handler-at-label-invalid-prompt","errorCode":null,"errorMessage":"Invalid managed hook handler at ${label}: invalid prompt","messagePattern":"Invalid managed hook handler at (.+?): invalid prompt","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/install/claude-settings.js","lineNumber":120,"sourceCode":"    }\n    if (\n      hook.headers !== undefined\n      && (!isJsonObject(hook.headers)\n        || !Object.values(hook.headers).every(value => typeof value === 'string'))\n    ) {\n      throw new Error(`Invalid managed hook handler at ${label}: invalid headers`);\n    }\n    if (\n      hook.allowedEnvVars !== undefined\n      && (!Array.isArray(hook.allowedEnvVars)\n        || !hook.allowedEnvVars.every(isNonEmptyString))\n    ) {\n      throw new Error(`Invalid managed hook handler at ${label}: invalid allowedEnvVars`);\n    }\n    return;\n  }\n  if (!isNonEmptyString(hook.prompt)) {\n    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}\"`);","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/install/claude-settings.js#L102-L138","documentation":"Hooks that are not of type 'command' or 'http' (i.e. prompt/agent hooks) must have a 'prompt' field that is a non-empty string. validateHookHandler throws this error when such a hook lacks prompt, has a blank prompt, or prompt is a non-string value.","triggerScenarios":"validateManagedHooks encounters {type:'prompt'} with no prompt, {type:'prompt', prompt:''}, {type:'prompt', prompt:[\"step1\",\"step2\"]}, or {type:'agent', agent:'reviewer'} missing prompt.","commonSituations":"Prompt hooks authored with the instruction text under another key (instruction, message, text); multi-line prompts stored as arrays; copying a command hook and forgetting to add prompt; empty prompt after template variable substitution.","solutions":["Add a non-empty prompt string: {type:'prompt', prompt:'Review the staged diff for security issues'}.","Rename instruction/message/text keys to prompt.","Join any array-of-lines into a single string (e.g. lines.join('\\n')).","Check that template interpolation did not produce an empty string."],"exampleFix":"// before\n{ \"type\": \"prompt\", \"instruction\": \"Summarize the changes\" }\n// after\n{ \"type\": \"prompt\", \"prompt\": \"Summarize the changes\" }","handlingStrategy":"validation","validationCode":"const bad = hooks.filter(h=>h.type!=='command'&&h.type!=='http'&&!(typeof h.prompt==='string'&&h.prompt.trim()!=='')); if (bad.length) throw new Error('prompt hooks need non-empty prompt');","typeGuard":"const hasPrompt = (h) => ['command','http'].includes(h.type) || (typeof h.prompt === 'string' && h.prompt.trim() !== '');","tryCatchPattern":"try { installHooks(cfg); } catch (e) { if (e.message.includes('invalid prompt')) { console.error('Prompt/agent hook missing prompt text:', e.message); process.exitCode = 1; } else throw e; }","preventionTips":["Name the field 'prompt' (not instruction/text/message).","Join multiline prompt arrays into one string.","Check template substitution leaves non-empty prompt."],"tags":["config","validation","hooks"],"backgroundTag":"missing-required-config-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"}