affaan-m/ECC · error
At least one guided harness must be selected
Error message
At least one guided harness must be selected
What it means
normalizeHarnessSelection validates a guided harness selection string/array and throws when it is empty or every token normalizes to 'none' — the interactive installer requires at least one harness to configure. It is called by installer prompts and helpers (askHarnesses, normalizedHarnesses, etc.).
Solutions
- Provide at least one harness token, e.g. --harnesses claude-code or --harnesses all.
- If you truly want no harness integration, skip the guided harness step rather than passing 'none'.
- Check the scripted invocation for an unset/empty variable feeding the selection.
- Use the interactive prompt and select the harnesses you use.
Example fix
// before const selection = process.env.HARNESSES || ''; // empty -> throws const ids = normalizeHarnessSelection(selection); // after const selection = process.env.HARNESSES || 'claude-code'; const ids = normalizeHarnessSelection(selection);
Defensive patterns
Strategy: validation
Validate before calling
const tokens = String(selection || '').split(',').map(t => t.trim()).filter(Boolean);
if (tokens.length === 0 || tokens.every(t => t.toLowerCase() === 'none')) {
throw new Error('Provide at least one harness (e.g. claude-code) or "all"');
} Type guard
function hasHarnessSelection(sel) {
const tokens = Array.isArray(sel) ? sel : String(sel || '').split(',');
return tokens.some(t => String(t).trim() && String(t).trim().toLowerCase() !== 'none');
} Try / catch
try {
const ids = normalizeHarnessSelection(selection);
} catch (e) {
if (/At least one guided harness/.test(e.message)) {
console.error('Re-run with --harnesses <name> or --harnesses all');
process.exitCode = 2;
return;
}
throw e;
} Prevention
- Default scripted invocations to a concrete harness instead of an empty string.
- Validate the harnesses flag at CLI-parse time with a clear usage message.
- Skip the guided harness step entirely when no integration is wanted, rather than passing 'none'.
When it happens
Trigger: Invoking the guided installer with an empty selection, pressing enter with no input at the harness prompt, passing 'none' (or only whitespace/commas), or programmatically calling selectedHarnessIds([]) / normalizeHarnessSelection('').
Common situations: Users running the non-interactive installer with --harnesses "" or --harnesses none; scripting the installer where a variable holding the harness list is unset; CI configs where the harness flag was dropped during refactoring.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- No install profile, module IDs, included components, or…
- No install profile, module IDs, or included component IDs…
- No legacy languages were provided
- The all/* harness selection cannot be combined with other…
- all overlays must be readable local files
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/1e6c113812c6c39c.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/harness-capabilities.js:331
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 8321021c54)