affaan-m/ECC · error · Error

Invalid ECC repo root: missing install script at

Error message

Invalid ECC repo root: missing install script at ${installApplyPath}

What it means

readRegularTextFile opens files with O_NOFOLLOW|O_NONBLOCK and then fstat's the descriptor to confirm the opened object is a regular file. If the fstat shows it is not a regular file (device, fifo, socket, directory), it throws this error naming the file via label. This guarantees reads only ever consume plain regular files and never special files that could block forever or leak data.

Solutions

  1. Point the path at a regular file, not a directory, fifo, socket, or device node.
  2. Check the path with `ls -la` / `file <path>` to see what kind of filesystem object it actually is.
  3. Fix the configuration key or constant that supplies the wrong path.
  4. If data lives in a directory, read the specific file inside it instead of the directory itself.

Example fix

// before
readBody('/vault/project');            // directory

// after
readBody('/vault/project/memory.md'); // regular file
Defensive patterns

Strategy: type-guard

Validate before calling

const fs = require('fs');
function assertRegularFile(path) {
  const st = fs.lstatSync(path);
  if (!st.isFile()) {
    throw new TypeError(`Expected a regular file at ${path}, got ${st.isDirectory() ? 'directory' : 'special file'}.`);
  }
}

Type guard

const isRegularFile = (p) => { try { return fs.lstatSync(p).isFile() && !fs.lstatSync(p).isSymbolicLink(); } catch { return false; } };

Try / catch

try {
  const text = readRegularTextFile(path, { label: 'memory document', maxBytes });
} catch (err) {
  if (err.message.includes('must be a regular, non-symlink file')) {
    throw new Error(`${path} is not a regular file — check the path/config key.`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing a path that is a FIFO, socket, device node (e.g. /dev/*), or directory to a reader that goes through readRegularTextFile (callers: existing, source, readBody). The O_NOFOLLOW open would already fail on a symlink, so reaching this check means the path itself is a non-regular file.

Common situations: A misconfigured path pointing at a named pipe or device; passing a directory where a file was expected (e.g. wrong config key); a test fixture accidentally creating a fifo; container mounts exposing special files at the expected path.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/df867170f7895525. Report an issue: GitHub.

Appendix: source

Thrown at scripts/auto-update.js:148

}

// Recognized ECC package names. A repo root is only trusted to run its
// install-apply.js if its package.json identifies it as ECC — otherwise a
// cloned project that ships a nested `evil/{package.json,scripts/install-apply.js}`
// could drive auto-update into executing attacker code (GHSA-hfpv-w6mp-5g95).
const ECC_PACKAGE_NAMES = new Set(['ecc-universal', 'everything-claude-code']);

function validateRepoRoot(repoRoot) {
  const normalized = path.resolve(repoRoot);
  const packageJsonPath = path.join(normalized, 'package.json');
  const installApplyPath = path.join(normalized, 'scripts', 'install-apply.js');

  if (!fs.existsSync(packageJsonPath)) {
    throw new Error(`Invalid ECC repo root: missing package.json at ${packageJsonPath}`);
  }

  if (!fs.existsSync(installApplyPath)) {
    throw new Error(`Invalid ECC repo root: missing install script at ${installApplyPath}`);
  }

  let pkgName = null;
  try {
    pkgName = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')).name;
  } catch {
    throw new Error(`Invalid ECC repo root: unreadable package.json at ${packageJsonPath}`);
  }
  if (!ECC_PACKAGE_NAMES.has(pkgName)) {
    throw new Error(`Refusing to run install from untrusted repo root ${normalized}: package.json name '${pkgName}' is not an official ECC package.`);
  }

  return normalized;
}

function runExternalCommand(command, args, options = {}) {
  const result = spawnSync(command, args, {
    cwd: options.cwd,

View on GitHub (pinned to 8321021c54)