affaan-m/ECC · error
Claude Code command contains characters that are unsafe for
Error message
Claude Code command contains characters that are unsafe for cmd.exe
What it means
Thrown by quoteWindowsCommandToken at scripts/lib/claude-plugin-setup.js:139-141 when a token in a Claude Code command line contains any character matched by UNSAFE_WINDOWS_SHELL_CHARS = /[\r\n&|<>^%!]/. The function is invoked from buildWindowsCommandLine, which is itself called from resolveWindowsCmdShim's spawn path when the original spawn failed and a .cmd/.bat shim must be invoked through cmd.exe (claude-plugin-setup.js:191-208). Because the spawn falls back to shell:true, ECC refuses any token that could break cmd.exe quoting or start a new command — this is an injection guard, not a formatting preference. The error is fatal: runClaude wraps it into a CLAUDE_COMMAND_FAILED ClaudeSetupError at claude-plugin-setup.js:197-203.
Source
Thrown at scripts/lib/claude-plugin-setup.js:140
|| typeof marketplace.source !== 'string'
|| !['github', 'git'].includes(marketplace.source)
|| !normalizeMarketplaceRepository(marketplace)
) {
fail(
'INVALID_MARKETPLACE_INVENTORY',
'Claude marketplace inventory contains an invalid `ecc` entry'
);
}
}
return marketplaces;
}
const UNSAFE_WINDOWS_SHELL_CHARS = /[\r\n&|<>^%!]/;
function quoteWindowsCommandToken(value) {
const token = String(value);
if (UNSAFE_WINDOWS_SHELL_CHARS.test(token)) {
throw new Error('Claude Code command contains characters that are unsafe for cmd.exe');
}
if (token === '') return '""';
if (!/[\s"]/.test(token)) return token;
return `"${token.replace(/"/g, '""')}"`;
}
function buildWindowsCommandLine(command, args) {
return [command, ...args].map(quoteWindowsCommandToken).join(' ');
}
function resolveWindowsCmdShim(command, env) {
if (typeof command !== 'string' || command.length === 0) return null;
if (/\.(cmd|bat)$/i.test(command)) return command;
if (path.extname(command)) return null;
const isPathLike = path.isAbsolute(command)
|| command.includes('/')
|| command.includes('\\');View on GitHub (pinned to 01e15490f0)
Solutions
- Inspect the args being passed to runClaude / spawnClaude and strip or URL-encode any of & | < > ^ % ! CR LF in path and URL tokens.
- Avoid percent-encoded characters in the OFFICIAL_MARKETPLACE_URL path on Windows; use a plain ASCII path.
- If the character lives in the project root path, run ECC setup from a path without shell metacharacters.
- On non-Windows hosts this guard never runs (resolveWindowsCmdShim returns null), so consider running setup under WSL or Git Bash with the .cmd shim disabled.
Example fix
// before
runClaude(['plugin', 'marketplace', 'add', 'https://github.com/x/y%20z'], { cwd: 'C:\repos\a&b' });
// after — quote-safe path and plain URL
runClaude(['plugin', 'marketplace', 'add', 'https://github.com/x/y'], { cwd: 'C:\\repos\\plain' }); Defensive patterns
Strategy: validation
Validate before calling
const UNSAFE = /[\r\n&|<>^%!]/;
function sanitizeWindowsToken(value) {
const s = String(value);
if (UNSAFE.test(s)) throw new Error(`token unsafe for cmd.exe: ${JSON.stringify(s)}`);
return s;
}
// before invoking claude on Windows
[command, ...args].forEach(sanitizeWindowsToken); Try / catch
try {
buildWindowsCommandLine(shim, args);
} catch (err) {
if (err.message === 'Claude Code command contains characters that are unsafe for cmd.exe') {
// identify the offending token and re-issue without it, or run on a non-Windows host
}
throw err;
} Prevention
- Avoid '%' in marketplace URLs and paths on Windows.
- URL-encode or strip shell metacharacters from any token derived from user input before spawning claude.
- Run ECC plugin setup from paths without &, |, !, ^ in any segment.
When it happens
Trigger: On Windows (process.platform === 'win32'), when a `claude` invocation fails (e.g. ENOENT on the bare 'claude' name), resolveWindowsCmdShim finds a `claude.cmd`, and buildWindowsCommandLine is asked to quote an arg containing & | < > ^ % ! or a CR/LF. Examples: a marketplace URL with a '%' (used in cmd variable expansion), an arg containing '&&', or an arg with an embedded newline.
Common situations: A plugin marketplace URL or repo path containing '%' (common in percent-encoded URLs passed unquoted); a project root path with a '!' (bash history expansion residue copied into a Windows path); a Claude config value containing '&' or '|'. The error surfaces during ECC setup on Windows when the Claude Code .cmd shim path is exercised.
Related errors
- ${EXECUTABLE_OVERRIDE} must be an absolute path explicitly c
- ${EXECUTABLE_OVERRIDE} does not point to a readable local It
- ${EXECUTABLE_OVERRIDE} must point to the canonical dist/bin/
- explicit --consent-to-openai is required
- 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/24338abb231cd2e8.
Report an issue: GitHub.