affaan-m/ECC · error · Error
Invalid ECC repo root: missing package.json at ${packageJson
Error message
Invalid ECC repo root: missing package.json at ${packageJsonPath} What it means
`changedFiles` is an optional field in the orch-review payload, but when present it must be an array of path strings — it is joined into the security-trigger haystack. This throw fires when changedFiles is supplied but is not an array (e.g. a single string, a comma-separated CSV string, or an object). Non-array values would not join correctly and would distort the security scan.
Source
Thrown at scripts/auto-update.js:136
return path.dirname(record.state.target.root);
}
return repoRoot;
}
// 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;
}View on GitHub (pinned to 01e15490f0)
Solutions
- Pass an array even for one file: changedFiles: ['src/foo.js'].
- If you have a CSV or Set, convert first: changedFiles: Array.from(fileSet) or csv.split(',').
- If you do not need file-level security scanning, omit changedFiles entirely.
Example fix
// before
orchReview({ diff, changedFiles: 'src/foo.js' }); // string, not array
// after
orchReview({ diff, changedFiles: ['src/foo.js'] }); Defensive patterns
Strategy: validation
Validate before calling
// Normalize changedFiles to an array before calling.
if (changedFiles != null && !Array.isArray(changedFiles)) {
changedFiles = [String(changedFiles)]; // or csv.split(',')
}
orchReview({ diff, changedFiles }); Type guard
function isValidChangedFiles(v) {
return v == null || (Array.isArray(v) && v.every(x => typeof x === 'string'));
} Prevention
- Always pass changedFiles as an array, even for a single file.
- Convert CSV/Sets to arrays before passing.
- Omit changedFiles entirely if you do not need file-level security scanning.
When it happens
Trigger: Passing changedFiles: 'src/foo.js' (single string); changedFiles: 'a.js,b.js' (CSV); changedFiles: { path: 'a.js' } (object).
Common situations: Caller has a single changed file and passes it bare instead of wrapping in an array; caller joins file paths into a CSV string; a mapping step returns the wrong shape.
Related errors
- Invalid ECC repo root: missing install script at ${installAp
- Unknown argument: ${arg}
- ECC_PROJECT_DIR must be a child path within /workspace.
- Unable to infer ECC repo root from install-state operations
- ${label} must be an array.
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/3c9980d0e5503fcd.
Report an issue: GitHub.