affaan-m/ECC · error · Error
Unable to start ${command}: ${error.message}
Error message
Unable to start ${command}: ${error.message} What it means
launchDetached wraps spawnImpl (child_process.spawn by default) in a try. If spawn throws synchronously — invalid command type, EACCES on the binary, EINVAL options — the error is re-thrown as 'Unable to start <command>: <message>' with the original error attached via { cause }. This is the synchronous spawn-failure path; asynchronous errors go through the child's 'error' event and the onDetachedError callback instead.
Source
Thrown at skills/terminal-opener/scripts/open-terminal.js:268
};
}
function reportDetachedError(error) {
process.stderr.write(`Error: ${error.message}\n`);
process.exitCode = 1;
}
function launchDetached(command, args, cwd, spawnImpl, onDetachedError) {
let child;
try {
child = spawnImpl(command, args, {
cwd,
detached: true,
shell: false,
stdio: 'ignore',
});
} catch (error) {
throw new Error(`Unable to start ${command}: ${error.message}`, { cause: error });
}
if (!child || typeof child.unref !== 'function') {
throw new Error('Terminal process did not start correctly.');
}
if (typeof child.once === 'function') {
child.once('error', error => {
onDetachedError(
new Error(`Unable to start ${command}: ${error.message}`, { cause: error })
);
});
}
child.unref();
}
function launch(plan, dependencies = {}) {
const spawnSyncImpl = dependencies.spawnSync || childProcess.spawnSync;
const spawnImpl = dependencies.spawn || childProcess.spawn;
const onDetachedError = dependencies.onDetachedError || reportDetachedError;View on GitHub (pinned to 01e15490f0)
Solutions
- Inspect error.cause for the original syscall error (EACCES, EINVAL, ENOENT).
- Ensure the wezterm binary is executable and on PATH (run --detect first).
- If injecting a custom spawnImpl dependency, ensure it returns a ChildProcess and only throws on genuine failures.
Defensive patterns
Strategy: try-catch
Try / catch
try {
launch(plan);
} catch (error) {
if (error.message.startsWith('Unable to start') && error.cause) {
log.error('terminal spawn failed', { code: error.cause.code, message: error.cause.message });
}
throw error;
} Prevention
- Run with --detect first to confirm the terminal binary is present and executable before --launch.
- Inspect error.cause for the underlying syscall error (EACCES, ENOENT, EINVAL).
- Ensure the wezterm binary is on PATH and executable in the environment that spawns the script.
When it happens
Trigger: spawnImpl(command, args, opts) throws synchronously inside launchDetached. Called from launch() for recover mode (line 293) and for the fallback after a failed mux spawn (line 314).
Common situations: wezterm binary present but not executable (EACCES); command argument of the wrong type; a custom injected spawnImpl that throws; ENOENT-style failures surfacing synchronously on some platforms.
Related errors
- Terminal process did not start correctly.
- ECC_PROJECT_DIR must be an absolute path within /workspace.
- Multiple ECC repo roots detected: ${uniqueRepoRoots.join(',
- README.md is missing the quick-start catalog summary
- Command "${commandName}" terminated by signal ${result.signa
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/66d428756d5286d2.
Report an issue: GitHub.