affaan-m/ECC · error · Error
At least one guided harness must be selected
Error message
At least one guided harness must be selected
What it means
Thrown by normalizeHarnessSelection() in scripts/lib/harness-capabilities.js when the input contains zero usable tokens, or every token normalizes to 'none'. The guided flow requires at least one harness to install for.
Source
Thrown at scripts/lib/harness-capabilities.js:317
function getHarnessCapability(value) {
if (typeof value !== 'string' || value.trim() === '') {
return null;
}
return LOOKUP.get(normalizeLookupToken(value)) || null;
}
function tokenizeSelection(selection) {
const values = Array.isArray(selection) ? selection : [selection];
return values.flatMap(value => (
typeof value === 'string' ? value.split(',') : []
)).map(value => value.trim()).filter(Boolean);
}
function normalizeHarnessSelection(selection) {
const tokens = tokenizeSelection(selection);
if (tokens.length === 0 || tokens.every(token => normalizeLookupToken(token) === 'none')) {
throw new Error('At least one guided harness must be selected');
}
const allTokens = tokens.filter(token => ['all', '*'].includes(normalizeLookupToken(token)));
const explicitTokens = tokens.filter(token => !['all', '*'].includes(normalizeLookupToken(token)));
if (allTokens.length > 0 && explicitTokens.length > 0) {
throw new Error('The all/* harness selection cannot be combined with other selections');
}
if (allTokens.length > 0) {
return GUIDED_HARNESS_IDS.slice();
}
const selected = new Set();
for (const token of tokens) {
const normalizedToken = normalizeLookupToken(token);
const menuIndex = /^\d+$/.test(normalizedToken) ? Number(normalizedToken) - 1 : -1;
const harness = menuIndex >= 0
? listGuidedHarnesses()[menuIndex] || null
: getHarnessCapability(token);View on GitHub (pinned to 01e15490f0)
Solutions
- Pass at least one guided harness id, e.g. 'claude', 'codex', or 'kimi' (the GUIDED_HARNESS_IDS set).
- Use 'all' or '*' to select every guided harness.
- If 'none' is intentional, handle it upstream before calling normalizeHarnessSelection rather than passing it through.
Example fix
// before
const sel = normalizeHarnessSelection(process.env.HARNESS_SELECTION);
// after
const raw = process.env.HARNESS_SELECTION || 'claude';
if (raw.trim().toLowerCase() === 'none') {
console.log('Skipping harness install');
return [];
}
const sel = normalizeHarnessSelection(raw); Defensive patterns
Strategy: validation
Validate before calling
function hasSelection(sel) {
const tokens = (Array.isArray(sel) ? sel : [sel])
.flatMap(v => typeof v === 'string' ? v.split(',') : [])
.map(v => v.trim()).filter(Boolean);
return tokens.length > 0 && !tokens.every(t => t.trim().toLowerCase() === 'none');
}
if (!hasSelection(process.env.HARNESS_SELECTION)) {
console.error('No harness selected; defaulting to claude');
} Try / catch
try {
return normalizeHarnessSelection(sel);
} catch (err) {
if (/At least one guided harness/.test(err.message)) {
return normalizeHarnessSelection('claude');
}
throw err;
} Prevention
- Default HARNESS_SELECTION to 'claude' (or 'all') at the CLI boundary.
- Treat 'none' as 'skip' upstream instead of forwarding to normalizeHarnessSelection.
- Validate selection presence in the CLI flag parser.
When it happens
Trigger: normalizeHarnessSelection(undefined), normalizeHarnessSelection(''), normalizeHarnessSelection([]), normalizeHarnessSelection('none'), or normalizeHarnessSelection('none,none'). After tokenizeSelection the array is empty or all tokens normalize to 'none'.
Common situations: CLI flag --harness not provided and defaulted to empty; user typed '--harness none' meaning skip; config file has harnesses: [] or harnesses: 'none'; env var HARNESS_SELECTION unset.
Related errors
- The all/* harness selection cannot be combined with other se
- Unknown guided harness selection: ${token}
- ${harness.label} is an advanced harness and is not guided-re
- Target '${target}' is supported, but the bare-language insta
- Refusing to run install from untrusted repo root ${normalize
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/1e6c113812c6c39c.
Report an issue: GitHub.