parcel-bundler/parcel · error · FSError

ENOENT

ENOENT

Error message

does not exist

What it means

Thrown by OverlayFS._deletedThrows() when the given filePath is in the `deleted` Set. OverlayFS layers a writable filesystem on top of a readable one; when a file is deleted via the overlay, it's not removed from the readable layer but instead added to the `deleted` set to mask it. Any subsequent access throws ENOENT to honor the deletion.

Source

Thrown at packages/core/fs/src/OverlayFS.js:66

  serialize(): {|
    $$raw: boolean,
    readable: FileSystem,
    writable: FileSystem,
    deleted: Set<FilePath>,
  |} {
    return {
      $$raw: false,
      writable: this.writable,
      readable: this.readable,
      deleted: this.deleted,
    };
  }

  _deletedThrows(filePath: FilePath): FilePath {
    filePath = this._normalizePath(filePath);
    if (this.deleted.has(filePath)) {
      throw new FSError('ENOENT', filePath, 'does not exist');
    }
    return filePath;
  }

  _checkExists(filePath: FilePath): FilePath {
    filePath = this._deletedThrows(filePath);
    if (!this.existsSync(filePath)) {
      throw new FSError('ENOENT', filePath, 'does not exist');
    }
    return filePath;
  }

  _isSymlink(filePath: FilePath): boolean {
    filePath = this._normalizePath(filePath);
    // Check the parts of the path to see if any are symlinks.
    let {root, dir, base} = path.parse(filePath);
    let segments = dir.slice(root.length).split(path.sep).concat(base);
    while (segments.length) {

View on GitHub (pinned to 59484858a1)

Solutions

  1. Check `overlayFS.deleted.has(filePath)` before accessing a path that may have been deleted.
  2. Use existsSync on the OverlayFS which accounts for the deleted set rather than checking the underlying readable layer directly.
  3. If you need to restore a deleted file, create a new OverlayFS instance or remove the path from the deleted set programmatically.

Example fix

// before
let content = await overlayFS.readFile(filePath); // throws if deleted

// after
if (!overlayFS.deleted.has(path.normalize(filePath))) {
  let content = await overlayFS.readFile(filePath);
}
Defensive patterns

Strategy: validation

Validate before calling

// Check deleted set before accessing OverlayFS paths
function isDeleted(overlayFS, filePath) {
  const normalized = overlayFS._normalizePath(filePath);
  return overlayFS.deleted.has(normalized);
}

// Usage:
if (!isDeleted(overlayFS, filePath)) {
  await overlayFS.readFile(filePath);
}

Type guard

// Guard: check if the filesystem is an OverlayFS with a deleted Set
function isOverlayFS(fs) {
  return fs instanceof Object &&
    fs.deleted instanceof Set &&
    'writable' in fs &&
    'readable' in fs;
}

Try / catch

try {
  await overlayFS.readFile(filePath);
} catch (e) {
  if (e.code === 'ENOENT' && overlayFS.deleted.has(overlayFS._normalizePath(filePath))) {
    // File was logically deleted — recreate or skip
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling any OverlayFS read/write/stat method that internally calls _deletedThrows on a path previously removed via `overlayFS.unlink()` or `overlayFS rimraf()`. The deleted Set persists for the lifetime of the OverlayFS instance.

Common situations: A Parcel build deletes a cached asset file, then a later stage (or re-run) tries to read it without clearing the deleted state. Hot-module replacement (HMR) logic deletes a file on change, then a stale reference tries to re-read it. Cache invalidation doesn't clear the deleted set, causing false ENOENT on files that still exist in the readable layer.

Related errors


AI-assisted analysis of parcel-bundler/parcel@59484858a1 (2026-08-13). Data as JSON: /api/errors/b08b4499a4c4292b. Report an issue: GitHub.