affaan-m/ECC · error · Error
Refusing to invoke an Itô CLI shim. Set…
Error message
Refusing to invoke an Itô CLI shim. Set ECC_ITO_CLI_EXECUTABLE to the absolute dist/bin/ito.js path.
What it means
buildInvocation is the last line of defense before the bridge spawns the Itô CLI: it re-validates that the resolved executable is the canonical dist/bin/ito.js and refuses anything else. This guards against shims or wrappers intercepting a credential-bearing client, since ECC deliberately never discovers the CLI through PATH.
Solutions
- Set ECC_ITO_CLI_EXECUTABLE to the absolute canonical path .../cli/ito-compute-cli/dist/bin/ito.js and remove any wrapper indirection.
- Apply env vars or logging around the invocation (e.g. in the shell that launches ECC) instead of wrapping the CLI binary itself.
- Rebuild from the canonical repo if you need customization; do not point ECC at a renamed/copied entry.
- Confirm no script or profile rewrites ECC_ITO_CLI_EXECUTABLE after your export (check shell rc files and CI env).
Example fix
// before export ECC_ITO_CLI_EXECUTABLE=/usr/local/bin/ito-wrapper # shim // after unset ITO_WRAPPER; export ECC_ITO_CLI_EXECUTABLE=/opt/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito.js
Defensive patterns
Strategy: validation
Validate before calling
const override = process.env.ECC_ITO_CLI_EXECUTABLE;
if (override && !override.endsWith('/cli/ito-compute-cli/dist/bin/ito.js')) {
throw new Error('Override must be the absolute dist/bin/ito.js path, not a shim');
} Type guard
const isCanonicalEntry = (p) => typeof p === 'string' && /\/cli\/ito-compute-cli\/dist\/bin\/ito\.js$/.test(p);
Try / catch
try { await eccIto(['status']); } catch (e) { if (e.message.includes('Refusing to invoke an Itô CLI shim')) { console.error('Remove the wrapper and set ECC_ITO_CLI_EXECUTABLE to dist/bin/ito.js'); } else throw e; } Prevention
- Do not wrap the CLI in shell scripts; apply env/logging in the launching shell instead
- Grep shell rc files and CI configs for rewrites of ECC_ITO_CLI_EXECUTABLE
- Treat the canonical-entry requirement as a security invariant, not an inconvenience
When it happens
Trigger: Any ecc ito command where the executable handed to buildInvocation (via resolveItoExecutable/invocation) is not the canonical entry — e.g. the override was changed between validation and invocation, or a modified caller passes a shim path directly.
Common situations: Users wrapping the CLI in shell wrappers for logging or env injection; patched forks that relax earlier checks; CI images that substitute a downloaded binary.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- ECC_ITO_CLI_EXECUTABLE must point to the canonical…
- An install config path is required
- Path ' ' targets a system directory
- Refusing to invoke an Itô CLI shim. Set
- The canonical ito-compute-cli is unpublished and ECC will…
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/92687b081eeaebdf.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/ito.js:257
? segment.toLowerCase() === expected.toLowerCase()
: segment === expected;
});
}
function isUsableExecutable(candidate) {
try {
const info = fs.statSync(candidate);
if (!info.isFile()) return false;
fs.accessSync(candidate, fs.constants.R_OK);
return true;
} catch {
return false;
}
}
function buildInvocation(executable, args) {
if (!isCanonicalItoEntry(executable)) {
throw new Error(
`Refusing to invoke an Itô CLI shim. Set ${EXECUTABLE_OVERRIDE} to the absolute dist/bin/ito.js path.`
);
}
return Object.freeze({
executable: process.execPath,
args: Object.freeze([executable, ...args]),
});
}
function invokeIto(executable, args, environment = process.env) {
const invocation = buildInvocation(executable, args);
const command = getInvocationCommand(args);
const isNodeQualification = command === "evals";
const isDeviceLogin = command === "login";
const result = spawnSync(invocation.executable, invocation.args, {
cwd: process.cwd(),
encoding: "utf8",
// Keep policy helpers immutable for callers, but give child-processView on GitHub (pinned to 8321021c54)