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
- Point the path at a regular file, not a directory, fifo, socket, or device node.
- Check the path with `ls -la` / `file <path>` to see what kind of filesystem object it actually is.
- Fix the configuration key or constant that supplies the wrong path.
- 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
- Verify paths with `file`/`ls -la` when configuring vault locations.
- Ensure config keys point at files, not directories or pipes.
- Guard call sites with an isRegularFile check before reading.
- Avoid pointing the vault at special filesystem paths (devices, fifos, sockets).
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
- Invalid ECC repo root: unreadable package.json at
- gate.variant_invalid
- Invalid ECC repo root: missing package.json at
- Memory destination changed while it was being created.
- output artifact must be a regular file
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)