affaan-m/ECC · error · Error
Unsupported guided harness: ${id}
Error message
Unsupported guided harness: ${id} What it means
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.
Source
Thrown at scripts/lib/multi-harness-setup.js:394
}
async function createMultiHarnessPlan(request, injected = {}, options = {}) {
const dependencies = { ...defaultDependencies(options), ...injected };
let entries = [];
for (const id of request.harnesses) {
if (id === 'claude') {
entries = [...entries, { id, channel: 'native-plugin', preview: await dependencies.previewClaude(request) }];
} else if (id === 'codex') {
entries = [...entries, { id, channel: 'native-plugin', preview: await dependencies.previewCodex(request) }];
} else if (id === 'kimi') {
const managedPlan = await dependencies.createManagedPlan(request);
entries = [...entries, {
id,
channel: 'managed-project',
preview: await dependencies.preflightManaged(managedPlan),
}];
} else {
throw new Error(`Unsupported guided harness: ${id}`);
}
}
return { harnesses: entries, request };
}
async function applyMultiHarnessPlan(plan, injected = {}, options = {}) {
const dependencies = { ...defaultDependencies(options), ...injected };
if (plan.request.dryRun) {
return { status: 'preview', completed: [], retryHarnesses: [...plan.request.harnesses] };
}
let completed = [];
for (let index = 0; index < plan.harnesses.length; index += 1) {
const entry = plan.harnesses[index];
try {
let result;
if (entry.id === 'claude') result = await dependencies.applyClaude(plan.request, entry);
else if (entry.id === 'codex') result = await dependencies.applyCodex(plan.request, entry);View on GitHub (pinned to 01e15490f0)
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.
Example fix
// before: caller bypasses normalization
const plan = await createMultiHarnessPlan({ harnesses: ['cursor'] }); // throws [295]
// after: validate via the normalizer, which only allows claude/codex/kimi
const req = normalizeGuidedInstallRequest({ harnesses: ['claude','kimi'] });
const plan = await createMultiHarnessPlan(req); Defensive patterns
Strategy: validation
Validate before calling
const SUPPORTED = new Set(['claude','codex','kimi']);
function assertSupportedHarnesses(harnesses) {
const bad = harnesses.filter(id => !SUPPORTED.has(id));
if (bad.length) throw new Error(`Unsupported harness id(s): ${bad.join(', ')}. Supported: claude, codex, kimi.`);
}
assertSupportedHarnesses(request.harnesses);
// or simply route through normalizeGuidedInstallRequest, which validates for you
const safeReq = normalizeGuidedInstallRequest({ harnesses: request.harnesses }); Type guard
function isSupportedHarness(id) {
return id === 'claude' || id === 'codex' || id === 'kimi';
} Try / catch
try {
await createMultiHarnessPlan(req);
} catch (err) {
if (/Unsupported guided harness/.test(err.message)) {
req.harnesses = req.harnesses.filter(isSupportedHarness);
if (!req.harnesses.length) throw new Error('No supported harnesses selected.');
await createMultiHarnessPlan(req);
} else throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ECC_PROJECT_DIR must be a child path within /workspace.
- Unknown argument: ${arg}
- Unable to infer ECC repo root from install-state operations
- Invalid ECC repo root: missing package.json at ${packageJson
- Invalid ECC repo root: missing install script at ${installAp
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/25598329f26c76fe.
Report an issue: GitHub.