{"record":{"id":"25598329f26c76fe","repo":"affaan-m/ECC","slug":"unsupported-guided-harness-id","errorCode":null,"errorMessage":"Unsupported guided harness: ${id}","messagePattern":"Unsupported guided harness: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/multi-harness-setup.js","lineNumber":394,"sourceCode":"}\n\nasync function createMultiHarnessPlan(request, injected = {}, options = {}) {\n  const dependencies = { ...defaultDependencies(options), ...injected };\n  let entries = [];\n  for (const id of request.harnesses) {\n    if (id === 'claude') {\n      entries = [...entries, { id, channel: 'native-plugin', preview: await dependencies.previewClaude(request) }];\n    } else if (id === 'codex') {\n      entries = [...entries, { id, channel: 'native-plugin', preview: await dependencies.previewCodex(request) }];\n    } else if (id === 'kimi') {\n      const managedPlan = await dependencies.createManagedPlan(request);\n      entries = [...entries, {\n        id,\n        channel: 'managed-project',\n        preview: await dependencies.preflightManaged(managedPlan),\n      }];\n    } else {\n      throw new Error(`Unsupported guided harness: ${id}`);\n    }\n  }\n  return { harnesses: entries, request };\n}\n\nasync function applyMultiHarnessPlan(plan, injected = {}, options = {}) {\n  const dependencies = { ...defaultDependencies(options), ...injected };\n  if (plan.request.dryRun) {\n    return { status: 'preview', completed: [], retryHarnesses: [...plan.request.harnesses] };\n  }\n\n  let completed = [];\n  for (let index = 0; index < plan.harnesses.length; index += 1) {\n    const entry = plan.harnesses[index];\n    try {\n      let result;\n      if (entry.id === 'claude') result = await dependencies.applyClaude(plan.request, entry);\n      else if (entry.id === 'codex') result = await dependencies.applyCodex(plan.request, entry);","sourceCodeStart":376,"sourceCodeEnd":412,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/multi-harness-setup.js#L376-L412","documentation":"Thrown by createMultiHarnessPlan when request.harnesses contains an id that is not 'claude', 'codex', or 'kimi'. The guided installer only supports those three harnesses; an unknown id means the request was malformed upstream. normalizeGuidedInstallRequest is supposed to validate the harness list earlier, so reaching this branch implies the harness array was injected/modified after normalization or normalization was bypassed.","triggerScenarios":"Fires in the else branch of the harness id chain in createMultiHarnessPlan. Reached when an id in request.harnesses is not one of the three supported strings. Happens if a caller constructs the request manually without normalizeGuidedInstallRequest, passes uppercase/whitespace variants that bypassed normalization, or forwards an id from user input not in the allowed set.","commonSituations":"Caller builds {harnesses:['cursor']} or ['windsurf'] directly; case mismatch like 'Claude' if normalization was skipped; user-supplied harness name forwarded to createMultiHarnessPlan without validation; programmatic integration that extended harnesses without updating this dispatcher.","solutions":["Route user input through normalizeGuidedInstallRequest first; it rejects unsupported harnesses early with a clearer message.","Restrict request.harnesses to the set ['claude','codex','kimi'].","If you need to add a harness, extend this dispatcher and the normalizer together — do not pass an unknown id.","Check for case/whitespace in the id and normalize to lowercase before dispatch."],"exampleFix":"// before: caller bypasses normalization\nconst plan = await createMultiHarnessPlan({ harnesses: ['cursor'] }); // throws [295]\n\n// after: validate via the normalizer, which only allows claude/codex/kimi\nconst req = normalizeGuidedInstallRequest({ harnesses: ['claude','kimi'] });\nconst plan = await createMultiHarnessPlan(req);","handlingStrategy":"validation","validationCode":"const SUPPORTED = new Set(['claude','codex','kimi']);\nfunction assertSupportedHarnesses(harnesses) {\n  const bad = harnesses.filter(id => !SUPPORTED.has(id));\n  if (bad.length) throw new Error(`Unsupported harness id(s): ${bad.join(', ')}. Supported: claude, codex, kimi.`);\n}\nassertSupportedHarnesses(request.harnesses);\n// or simply route through normalizeGuidedInstallRequest, which validates for you\nconst safeReq = normalizeGuidedInstallRequest({ harnesses: request.harnesses });","typeGuard":"function isSupportedHarness(id) {\n  return id === 'claude' || id === 'codex' || id === 'kimi';\n}","tryCatchPattern":"try {\n  await createMultiHarnessPlan(req);\n} catch (err) {\n  if (/Unsupported guided harness/.test(err.message)) {\n    req.harnesses = req.harnesses.filter(isSupportedHarness);\n    if (!req.harnesses.length) throw new Error('No supported harnesses selected.');\n    await createMultiHarnessPlan(req);\n  } else throw err;\n}","preventionTips":["Always build requests via normalizeGuidedInstallRequest rather than hand-constructing them.","Restrict UI inputs to the supported set; disable free-text harness names.","Lowercase and trim harness ids before dispatch.","When extending ECC with a new harness, update the dispatcher and normalizer together."],"tags":["multi-harness","validation","request-validation","unsupported-harness"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}