affaan-m/ECC · error · Error

must be a regular, non-symlink file.

Error message

${label} must be a regular, non-symlink file.

What it means

readRegularTextFile throws when the opened descriptor is not a regular file (directory, FIFO, device, or symlink target), after opening with O_NOFOLLOW/O_NONBLOCK. It hardens memory-vault reads against special-file abuse; the faulting input is the path in `label`.

Solutions

  1. Point the read at a regular file, not a directory or special file.
  2. Remove/replace symlinks in the memory path with real files.
  3. Check the caller for a wrong path suffix (e.g. passing a directory).
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at scripts/lib/memory-vault.js:156 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/1df467602b3decf6. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/memory-vault.js:156

  }
  return left.dev === right.dev;
}

function readRegularTextFile(filePath, options = {}) {
  const label = options.label || 'file';
  const maxBytes = options.maxBytes || MAX_DOCUMENT_BYTES;
  if (options.trustedRoot) {
    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;

View on GitHub (pinned to 8321021c54)