{"record":{"id":"ac109940757332c9","repo":"affaan-m/ECC","slug":"invalid-managed-hook-handler-at-label-invalid-headers","errorCode":null,"errorMessage":"Invalid managed hook handler at ${label}: invalid headers","messagePattern":"Invalid managed hook handler at (.+?): invalid headers","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/install/claude-settings.js","lineNumber":108,"sourceCode":"    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'))\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","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/install/claude-settings.js#L90-L126","documentation":"For http hooks, the optional 'headers' field must be a plain JSON object whose values are all strings. validateHookHandler throws this error when headers is an array, a non-plain object, or contains non-string values (numbers, booleans, nested objects).","triggerScenarios":"validateManagedHooks encounters {type:'http', url:'x', headers:[]} or headers:{'X-Retries':3} or headers:{auth:{token:'abc'}} or a class instance from a config loader.","commonSituations":"Numeric header values (retries, timeouts) that must be strings per HTTP semantics; YAML config where a header table parsed into nested maps; using headers to smuggle config instead of actual header names; passing a Headers instance from fetch instead of a plain object.","solutions":["Make headers a plain object mapping header names to string values: {\"Authorization\":\"Bearer ...\",\"X-Custom\":\"v1\"}.","Stringify any numeric or boolean values: \"X-Retries\": \"3\".","Flatten nested header objects into flat string entries.","Ensure the config loader deserializes to plain objects (JSON.parse / safe yaml load with plain schema)."],"exampleFix":"// before\n{ \"type\": \"http\", \"url\": \"https://api.example.com\", \"headers\": { \"X-Retries\": 3 } }\n// after\n{ \"type\": \"http\", \"url\": \"https://api.example.com\", \"headers\": { \"X-Retries\": \"3\" } }","handlingStrategy":"validation","validationCode":"const bad = hooks.filter(h=>h.type==='http'&&h.headers!==undefined&&(!isPlainObj(h.headers)||!Object.values(h.headers).every(v=>typeof v==='string'))); if (bad.length) throw new Error('headers must be a string-valued object');","typeGuard":"const hasValidHeaders = (h) => h.headers === undefined || (typeof h.headers === 'object' && !Array.isArray(h.headers) && Object.values(h.headers).every(v => typeof v === 'string'));","tryCatchPattern":"try { installHooks(cfg); } catch (e) { if (e.message.includes('invalid headers')) { console.error('HTTP hook headers must be flat name->string map:', e.message); process.exitCode = 1; } else throw e; }","preventionTips":["Stringify all header values, including numbers.","Do not pass fetch Headers instances; use plain objects.","Flatten nested header groups before install."],"tags":["config","validation","types"],"backgroundTag":"config-type-mismatch","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"}