affaan-m/ECC · error · Error
must point to the canonical dist/bin/ito.js entry.
Error message
${EXECUTABLE_OVERRIDE} must point to the canonical dist/bin/ito.js entry. What it means
After realpath succeeds, isCanonicalItoEntry verifies that the normalized absolute path ends with the exact canonical segment sequence CANONICAL_ENTRY_SEGMENTS (dist/bin/ito.js beneath cli/ito-compute-cli — see scripts/ito.js:16). This rejects wrappers, renamed entries, and alternative launchers so ECC only ever execs the audited entry file. Any path whose trailing segments do not match exactly fails here.
Solutions
- Point the variable at the exact built entry: <repo>/cli/ito-compute-cli/dist/bin/ito.js.
- If your build writes elsewhere, symlink or copy the artifact so the real path ends in cli/ito-compute-cli/dist/bin/ito.js, then point there.
- Run `node -e "console.log(require('fs').realpathSync.native(process.env.ECC_ITO_CLI_EXECUTABLE))"` to see what path ECC actually checks.
Example fix
# before export ECC_ITO_CLI_EXECUTABLE="$HOME/src/ito-cloud-runtime/cli/ito-compute-cli/bin/ito.js" # after export ECC_ITO_CLI_EXECUTABLE="$HOME/src/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito.js"
Defensive patterns
Strategy: validation
Validate before calling
import path from 'node:path';
const CANONICAL_SUFFIX = path.join('cli', 'ito-compute-cli', 'dist', 'bin', 'ito.js');
function isCanonicalEntry(p) {
return path.normalize(p).endsWith(CANONICAL_SUFFIX);
}
function assertCanonicalItoEntry(p) {
if (!isCanonicalEntry(p)) throw new Error(`Expected path ending in ${CANONICAL_SUFFIX}, got ${p}`);
return p;
} Type guard
function isCanonicalItoEntryPath(p) {
return typeof p === 'string' && path.normalize(p).endsWith(path.join('cli', 'ito-compute-cli', 'dist', 'bin', 'ito.js'));
} Prevention
- Always point the env var at the built dist/bin/ito.js, never bin/, src/, or a renamed copy.
- Note that symlinks are resolved first — the underlying real path must end in the canonical segments.
When it happens
Trigger: Pointing ECC_ITO_CLI_EXECUTABLE at the package root, bin/ito.js (a source-level shim) instead of dist/bin/ito.js, a copied/renamed ito.js, or an out-directory like build/bin/ito.js.
Common situations: Operators 'simplifying' the path or symlinking a friendly name like ~/.local/bin/ito-cli (realpath resolves it, but the underlying path must still end in the canonical segments); custom fork builds writing to a different out dir.
Related errors
- Announcements discussion category is required
- artifact path must be canonical and absolute
- Choose at least one guided harness: Claude, Codex, or Kimi.
- config must be a JSON object
- createPlanCanvasServer requires a session store
AI-assisted analysis of affaan-m/ECC@06c5e118c4 (2026-08-18).
Data as JSON: /api/errors/71265d98b6a980c3.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/ito.js:217
if (!path.isAbsolute(configured)) {
throw new Error(
`${EXECUTABLE_OVERRIDE} must be an absolute path explicitly configured by the operator.`
);
}
return assertUsableExecutable(configured);
}
function assertUsableExecutable(candidate) {
let canonicalCandidate;
try {
canonicalCandidate = fs.realpathSync.native(candidate);
} catch {
throw new Error(
`${EXECUTABLE_OVERRIDE} does not point to a readable local Itô CLI file.`
);
}
if (!isCanonicalItoEntry(canonicalCandidate)) {
throw new Error(
`${EXECUTABLE_OVERRIDE} must point to the canonical dist/bin/ito.js entry.`
);
}
if (!isUsableExecutable(canonicalCandidate)) {
throw new Error(
`${EXECUTABLE_OVERRIDE} does not point to a readable local Itô CLI file.`
);
}
return canonicalCandidate;
}
function isCanonicalItoEntry(candidate) {
const pathSegments = path
.normalize(candidate)
.split(path.sep)
.filter(Boolean);
if (pathSegments.length < CANONICAL_ENTRY_SEGMENTS.length) return false;
const candidateTail = pathSegments.slice(-CANONICAL_ENTRY_SEGMENTS.length);View on GitHub (pinned to 06c5e118c4)