affaan-m/ECC · error · Error
must remain a regular, non-symlink file while it is opened.
Error message
${label} must remain a regular, non-symlink file while it is opened. What it means
readRegularTextFile re-checks the path with lstat after opening and throws when the file was swapped to a symlink, ceased to be a regular file, or its identity (dev) changed mid-read — a TOCTOU/race guard. The faulting input is the file at `label` being concurrently replaced.
Solutions
- Retry the read once no other process is rewriting the file.
- Exclude the memory vault from concurrent writers/sync tools during reads.
- Investigate what is swapping the file if this recurs — likely a sync or editor tool racing the vault.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at scripts/lib/memory-vault.js:164 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/5e32e46b37708e3b.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/memory-vault.js:164
assertWithinTrustedRoot(filePath, options.trustedRoot, `read ${label}`);
}
const flags = fs.constants.O_RDONLY
| (fs.constants.O_NOFOLLOW || 0)
| (fs.constants.O_NONBLOCK || 0);
const descriptor = fs.openSync(filePath, flags);
try {
const opened = fs.fstatSync(descriptor, { bigint: true });
if (!opened.isFile()) {
throw new Error(`${label} must be a regular, non-symlink file.`);
}
const after = fs.lstatSync(filePath, { bigint: true });
if (
after.isSymbolicLink()
|| !after.isFile()
|| !sameFileIdentity(after, opened)
) {
throw new Error(`${label} must remain a regular, non-symlink file while it is opened.`);
}
if (options.trustedRoot) {
assertWithinTrustedRoot(filePath, options.trustedRoot, `read ${label}`);
}
if (opened.size > BigInt(maxBytes)) {
throw new Error(`${label} is too large (${opened.size} bytes).`);
}
const chunks = [];
let total = 0;
while (total <= maxBytes) {
const buffer = Buffer.alloc(Math.min(64 * 1024, maxBytes + 1 - total));
const bytesRead = fs.readSync(descriptor, buffer, 0, buffer.length, null);
if (bytesRead === 0) break;
chunks.push(buffer.subarray(0, bytesRead));
total += bytesRead;
}
if (total > maxBytes) {View on GitHub (pinned to 8321021c54)