{"record":{"id":"4427bbe3af5f54b4","repo":"affaan-m/ECC","slug":"install-module-moduleid-has-invalid-targets-ex","errorCode":null,"errorMessage":"Install module ${moduleId} has invalid targets; expected an array of supported target ids","messagePattern":"Install module (.+?) has invalid targets; expected an array of supported target ids","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/install-manifests.js","lineNumber":231,"sourceCode":"    || options[key] === null\n    || options[key] === undefined\n  ) {\n    return null;\n  }\n\n  if (typeof options[key] !== 'string' || options[key].trim() === '') {\n    throw new Error(`${key} must be a non-empty string when provided`);\n  }\n\n  return options[key];\n}\n\nfunction readModuleTargetsOrThrow(module) {\n  const moduleId = module && module.id ? module.id : '<unknown>';\n  const targets = module && module.targets;\n\n  if (!Array.isArray(targets)) {\n    throw new Error(`Install module ${moduleId} has invalid targets; expected an array of supported target ids`);\n  }\n\n  const normalizedTargets = targets.map(target => (\n    typeof target === 'string' ? target.trim() : ''\n  ));\n\n  if (normalizedTargets.some(target => target.length === 0)) {\n    throw new Error(`Install module ${moduleId} has invalid targets; expected an array of supported target ids`);\n  }\n\n  const unsupportedTargets = normalizedTargets.filter(target => !SUPPORTED_INSTALL_TARGETS.includes(target));\n  if (unsupportedTargets.length > 0) {\n    throw new Error(\n      `Install module ${moduleId} has unsupported targets: ${unsupportedTargets.join(', ')}`\n    );\n  }\n\n  return normalizedTargets;","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/install-manifests.js#L213-L249","documentation":"readModuleTargetsOrThrow reads `module.targets` from install-modules.json. The field MUST be an array; anything else (string, object, null, undefined, number) is rejected up front. The check fires before any per-element validation, so this is specifically the wrong-shape failure.","triggerScenarios":"loadInstallManifests parses install-modules.json and an entry has `targets` as a string ('claude') or an object instead of `['claude']`. Triggered at load time for any code path that reads modules (resolveInstallModules, intersectTargets, listInstallComponents).","commonSituations":"Manifest hand-edited and the author wrote a scalar instead of an array; YAML-to-JSON converter collapsed a single-item array to a scalar; schema-validation disabled in CI; copy-paste from docs that showed shorthand syntax.","solutions":["Open manifests/install-modules.json and find the module whose id appears in the error.","Change `targets` to an array: `\"targets\": [\"claude\"]` (not `\"targets\": \"claude\"`).","Validate the file against the manifest schema before committing (`npm run catalog:sync` or the project's manifest validator).","Re-run `npm test` to catch manifest shape errors locally."],"exampleFix":"// before: { \"id\": \"rules-core\", \"targets\": \"claude\" }\n// after: { \"id\": \"rules-core\", \"targets\": [\"claude\"] }","handlingStrategy":"validation","validationCode":"function moduleHasArrayTargets(module) {\n  return Boolean(module && Array.isArray(module.targets));\n}\n// when loading manifests: manifests.modules.every(moduleHasArrayTargets)","typeGuard":"function isModuleWithArrayTargets(module) {\n  return Boolean(module && typeof module === 'object' && Array.isArray(module.targets));\n}","tryCatchPattern":"try {\n  loadInstallManifests({ repoRoot });\n} catch (err) {\n  if (/has invalid targets; expected an array/.test(err.message)) {\n    // fix the manifest entry by id, then retry\n  } else throw err;\n}","preventionTips":["Use the manifest JSON schema in editor/CI to enforce array types.","Avoid YAML-to-JSON pipelines that collapse single-item arrays.","Run `npm run catalog:sync` and `npm test` before committing manifest changes.","Code-review manifest edits for shape, not just content."],"tags":["manifest","validation","install","schema"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}