affaan-m/ECC · error

${EXECUTABLE_OVERRIDE} must point to the canonical dist/bin/

Error message

${EXECUTABLE_OVERRIDE} must point to the canonical dist/bin/ito.js entry.

What it means

Thrown by assertUsableExecutable at scripts/ito.js:216-219 when the realpath-resolved candidate does not end with the canonical entry segments cli/ito-compute-cli/dist/bin/ito.js (CANONICAL_ENTRY_SEGMENTS, case-insensitive on win32). isCanonicalItoEntry (ito.js:229-242) normalizes the path, splits on path.sep, and compares the trailing segments. This enforces that ECC is invoking the genuine canonical entry, not a similarly-named wrapper or a renamed fork — defense against an operator pointing at a hostile or stale CLI binary that happens to be a readable file.

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 01e15490f0)

Solutions

  1. Point ECC_ITO_CLI_EXECUTABLE at the genuine built entry inside the canonical clone: .../cli/ito-compute-cli/dist/bin/ito.js.
  2. If you symlinked the entry elsewhere, point ECC_ITO_CLI_EXECUTABLE at the symlink target's real location (realpath will resolve the link; the resolved path must still end in the canonical segments).
  3. Do not rename ito.js or move it out of dist/bin/.

Example fix

// before
$ export ECC_ITO_CLI_EXECUTABLE="$HOME/bin/my-ito.js"   # a renamed copy
// after
$ export ECC_ITO_CLI_EXECUTABLE="$HOME/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito.js"
Defensive patterns

Strategy: validation

Validate before calling

const path = require('path');
const CANONICAL_TAIL = ['cli', 'ito-compute-cli', 'dist', 'bin', 'ito.js'];
function isCanonicalEntry(candidate) {
  const segs = path.normalize(candidate).split(path.sep).filter(Boolean);
  if (segs.length < CANONICAL_TAIL.length) return false;
  const tail = segs.slice(-CANONICAL_TAIL.length);
  return tail.every((s, i) => process.platform === 'win32'
    ? s.toLowerCase() === CANONICAL_TAIL[i].toLowerCase()
    : s === CANONICAL_TAIL[i]);
}
function assertCanonical(candidate) {
  if (!isCanonicalEntry(candidate)) throw new Error(`path does not end with ${CANONICAL_TAIL.join('/')}`);
}

Prevention

When it happens

Trigger: ECC_ITO_CLI_EXECUTABLE resolves (realpath succeeds) but the resolved path's trailing segments are not exactly [cli, ito-compute-cli, dist, bin, ito.js]. Examples: pointing at a vendored copy under vendor/ito.js; pointing at dist/bin/ito-cli.js (renamed); pointing at a sibling package's entry.

Common situations: Operator copied the dist into a different layout (`~/bin/ito.js`); used a fork with a different package name; pointed at a custom wrapper script that requires the real entry; renamed the file during local hacking.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/71265d98b6a980c3. Report an issue: GitHub.