{"record":{"id":"b50659739e3a5d51","repo":"affaan-m/ECC","slug":"invalid-managed-hook-handler-at-label-invalid-command","errorCode":null,"errorMessage":"Invalid managed hook handler at ${label}: invalid command","messagePattern":"Invalid managed hook handler at (.+?): invalid command","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/install/claude-settings.js","lineNumber":88,"sourceCode":"\nfunction validateHookHandler(hook, label) {\n  if (!isJsonObject(hook)) {\n    throw new Error(`Invalid managed hook handler at ${label}: expected a JSON object`);\n  }\n  if (!VALID_HOOK_TYPES.has(hook.type)) {\n    throw new Error(`Invalid managed hook handler at ${label}: unsupported type`);\n  }\n  if (hook.timeout !== undefined && (typeof hook.timeout !== 'number' || hook.timeout < 0)) {\n    throw new Error(`Invalid managed hook handler at ${label}: invalid timeout`);\n  }\n\n  if (hook.type === 'command') {\n    const validCommand = isNonEmptyString(hook.command)\n      || (Array.isArray(hook.command)\n        && hook.command.length > 0\n        && hook.command.every(isNonEmptyString));\n    if (!validCommand) {\n      throw new Error(`Invalid managed hook handler at ${label}: invalid command`);\n    }\n    if (hook.async !== undefined && typeof hook.async !== 'boolean') {\n      throw new Error(`Invalid managed hook handler at ${label}: invalid async flag`);\n    }\n    return;\n  }\n\n  if (hook.async !== undefined) {\n    throw new Error(`Invalid managed hook handler at ${label}: async requires command type`);\n  }\n  if (hook.type === 'http') {\n    if (!isNonEmptyString(hook.url)) {\n      throw new Error(`Invalid managed hook handler at ${label}: invalid url`);\n    }\n    if (\n      hook.headers !== undefined\n      && (!isJsonObject(hook.headers)\n        || !Object.values(hook.headers).every(value => typeof value === 'string'))","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/install/claude-settings.js#L70-L106","documentation":"validateHookHandler validates each managed hook entry written into Claude settings.json. For a hook of type 'command', the 'command' field must be either a non-empty string or a non-empty array of non-empty strings. This error is thrown when hook.command is missing, empty, an empty array, or contains non-string/blank entries.","triggerScenarios":"Calling install/managed-hook APIs (via validateManagedHooks) with a handler {type:'command'} whose command is undefined, '', '   ', [], [null], [''], or a non-array non-string value like 42 or {cmd:'x'}.","commonSituations":"Hand-edited settings.json with a typo'd key (cmds instead of command); programmatically generated hooks where the command template resolved to empty; YAML/JSON configs converted where the command was moved to a different field; array-form command built by splitting an empty string producing [].","solutions":["Set hook.command to a non-empty string, e.g. {type:'command', command:'node hooks/my-hook.js'}.","If using array form, provide a non-empty array of non-empty strings, e.g. command:['node','hooks/my-hook.js'].","Check the field is literally named 'command' (not 'cmd', 'run', or 'script').","Run a pre-flight check that every command-type hook has a valid command before calling the install API.","Trim whitespace-only strings — isNonEmptyString rejects values that are blank after trim."],"exampleFix":"// before\n{ \"type\": \"command\", \"command\": \"\" }\n// after\n{ \"type\": \"command\", \"command\": \"node hooks/hooks.json-lint.js\" }","handlingStrategy":"validation","validationCode":"function isValidCommandHook(h){ return h.type==='command' && (typeof h.command==='string' && h.command.trim()!=='' || Array.isArray(h.command) && h.command.length>0 && h.command.every(c=>typeof c==='string' && c.trim()!=='')); }","typeGuard":"const isCommandHook = (h) => typeof h === 'object' && h !== null && h.type === 'command' && (typeof h.command === 'string' || Array.isArray(h.command));","tryCatchPattern":"try { materializeManagedHooks(desired); } catch (e) { if (String(e.message).includes('invalid command')) { console.error('A command hook has a missing/empty command field:', e.message); process.exitCode = 1; } else throw e; }","preventionTips":["Always pair type:'command' with a non-empty command field.","Prefer the string form of command for single executables.","Lint settings.json hooks with a JSON schema in CI.","Never build command arrays by splitting empty strings."],"tags":["config","validation","hooks"],"backgroundTag":"invalid-config-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"}