affaan-m/ECC · error · Error
Executable must be one argv entry, not an interpolated shell
Error message
Executable must be one argv entry, not an interpolated shell command string.
What it means
validateExecutable computes whether the value 'resembles an executable path' (it is absolute, or a path separator appears before any whitespace). If the value contains whitespace AND does not resemble a path, it is rejected. Rationale: launch always uses shell:false, so a whitespace-laden token is passed as one bogus argv entry rather than parsed as a command. This is the whitespace branch (line 62-65).
Source
Thrown at skills/terminal-opener/scripts/open-terminal.js:63
function validateCwd(value) {
if (value.includes('\0')) throw new Error('--cwd must not contain a NUL byte.');
if (!isAbsolutePath(value)) throw new Error('--cwd must be an absolute path.');
}
function validateExecutable(value) {
if (!value || /[\0\r\n]/.test(value)) {
throw new Error('Executable must be a non-empty argv entry without control bytes.');
}
const whitespaceIndex = value.search(/\s/);
const separatorIndexes = [value.indexOf('/'), value.indexOf('\\')].filter(index => index >= 0);
const firstSeparatorIndex = separatorIndexes.length > 0 ? Math.min(...separatorIndexes) : -1;
const resemblesExecutablePath = isAbsolutePath(value)
|| (firstSeparatorIndex >= 0 && (whitespaceIndex < 0 || firstSeparatorIndex < whitespaceIndex));
if (whitespaceIndex >= 0 && !resemblesExecutablePath) {
throw new Error(
'Executable must be one argv entry, not an interpolated shell command string.'
);
}
if (!resemblesExecutablePath && /[;&|<>`$]/.test(value)) {
throw new Error(
'Executable must be one argv entry, not an interpolated shell command string.'
);
}
}
function validateArgv(argv) {
for (const argument of argv) {
if (argument.includes('\0')) throw new Error('Arguments must not contain NUL bytes.');
}
}
function readValue(argv, index, option) {
const value = argv[index + 1];View on GitHub (pinned to 01e15490f0)
Solutions
- Put the executable as the first token after --, and pass each argument as its own token after that.
- If you genuinely need a shell command, invoke a shell explicitly: -- /bin/sh -c '<command>' (sh becomes the executable, -c and the string become args).
Example fix
# before node open-terminal.js -- "bash -c 'echo hi'" # after node open-terminal.js -- bash -c "echo hi"
Defensive patterns
Strategy: validation
Validate before calling
function isSingleArgvEntry(executable) {
if (!executable) return false;
const sep = [executable.indexOf('/'), executable.indexOf('\\')].filter(i => i >= 0);
const firstSep = sep.length ? Math.min(...sep) : -1;
const ws = executable.search(/\s/);
const pathLike = path.isAbsolute(executable) || (firstSep >= 0 && (ws < 0 || firstSep < ws));
return !ws || pathLike;
}
if (!isSingleArgvEntry(executable)) {
throw new Error('Pass executable and args as separate tokens after --');
} Prevention
- Never interpolate a shell command into the executable slot; tokenize it.
- If you need shell semantics, invoke /bin/sh -c explicitly as executable + args.
- Build argv programmatically (an array) instead of splitting a command string.
When it happens
Trigger: options.executable contains whitespace and is not path-like — e.g. a single token 'bash -c echo hi' passed as the executable. The executable slot should hold one argv entry only.
Common situations: Passing a shell command string instead of separating the executable and its args after --; copy-pasting a command line into the executable argument.
Related errors
- Invalid terminal name; use a simple adapter name such as wez
- --cwd must not contain a NUL byte.
- Executable must be a non-empty argv entry without control by
- Arguments must not contain NUL bytes.
- 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/e442133f5c619368.
Report an issue: GitHub.