affaan-m/ECC · error
Invalid mode "${mode}". Allowed modes: ${allowedModes.join('
Error message
Invalid mode "${mode}". Allowed modes: ${allowedModes.join(', ')} What it means
Thrown by buildAgentCatalog at scripts/lib/agent-compress.js:173-175 when options.mode is not in the allowedModes list (['catalog', 'summary', 'full']). buildAgentCatalog compresses ECC agent markdown files into a token-budgeted catalog; the mode selects how aggressively each agent is compressed (catalog = metadata only, summary = metadata + first paragraph, full = no compression). The mode defaults to 'catalog' when omitted (ito.js:171 — agent-compress.js:171), so this only fires when an explicit invalid value is supplied.
Source
Thrown at scripts/lib/agent-compress.js:174
}
const allowedModes = ['catalog', 'summary', 'full'];
/**
* Build a compressed catalog from a directory of agents.
*
* Modes:
* - 'catalog': name, description, tools, model only (~2-3k tokens for 27 agents)
* - 'summary': catalog + first paragraph summary (~4-5k tokens)
* - 'full': no compression, full body included
*
* Returns { agents: [], stats: { totalAgents, originalBytes, compressedBytes, compressedTokenEstimate, mode } }
*/
function buildAgentCatalog(agentsDir, options = {}) {
const mode = options.mode || 'catalog';
if (!allowedModes.includes(mode)) {
throw new Error(`Invalid mode "${mode}". Allowed modes: ${allowedModes.join(', ')}`);
}
const filter = options.filter || null;
let agents = loadAgents(agentsDir);
if (typeof filter === 'function') {
agents = agents.filter(filter);
}
const originalBytes = agents.reduce((sum, a) => sum + a.byteSize, 0);
let compressed;
if (mode === 'catalog') {
compressed = agents.map(compressToCatalog);
} else if (mode === 'summary') {
compressed = agents.map(compressToSummary);
} else {View on GitHub (pinned to 01e15490f0)
Solutions
- Use one of: 'catalog', 'summary', 'full' (case-sensitive lowercase).
- Omit mode entirely if you want the default ('catalog').
- If you need a different compression shape, add it to allowedModes at agent-compress.js:158 and wire a branch into the if/else at lines 188-200.
Example fix
// before
buildAgentCatalog(dir, { mode: 'compact' });
// after
buildAgentCatalog(dir, { mode: 'catalog' }); Defensive patterns
Strategy: type-guard
Validate before calling
const ALLOWED = new Set(['catalog', 'summary', 'full']);
function buildAgentCatalogSafe(dir, options = {}) {
const mode = options.mode || 'catalog';
if (!ALLOWED.has(mode)) throw new Error(`Invalid mode '${mode}'`);
return buildAgentCatalog(dir, { ...options, mode });
} Type guard
function isAgentCatalogMode(value) {
return typeof value === 'string'
&& ['catalog', 'summary', 'full'].includes(value);
} Prevention
- Default mode to undefined (the function defaults to 'catalog') rather than guessing a name.
- Where mode is configured externally (JSON/TOML), validate with isAgentCatalogMode before passing through.
- When adding a new mode, update allowedModes and the if/else dispatch together; add a test.
When it happens
Trigger: Calling buildAgentCatalog(agentsDir, { mode: 'compact' }), { mode: 'short' }, { mode: 'metadata' }, or any string other than catalog/summary/full. Also fires on typos like 'catlog' or 'Summry'.
Common situations: A caller invented a mode name not in the docs; a refactor renamed a mode but callers were not updated; a config file supplies the mode and a typo slipped in; programmatic callers passing options.compressAs under the wrong key.
Related errors
- Project memory .gitignore does not contain the required fail
- Choose at least one guided harness: Claude, Codex, or Kimi.
- Claude scope and hook options require Claude to be selected.
- The managed install profile requires Kimi to be selected.
- Invalid Claude scope: ${claudeScope}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/bf2352a78eb16c06.
Report an issue: GitHub.