parcel-bundler/parcel · error · FSError

ENOTEMPTY

ENOTEMPTY

Error message

ENOTEMPTY: ${path} isn't empty

What it means

ENOTEMPTY raised by `ExtendedMemoryFS._rmdir` when `rimraf`/`rmdir` is called (non-recursive) on a directory whose `readdir` returns one or more entries. Mirrors Node's `fs.rmdir` non-empty semantics.

Source

Thrown at packages/dev/repl/src/parcel/ExtendedMemoryFS.js:167

    return super.mkdirp(dir);
  }

  async _rmdir(
    filePath: FilePath,
    options: {recursive?: boolean, ...} = {},
  ): Promise<void> {
    let {recursive = false} = options;

    if (!recursive) {
      if (!this.dirs.has(filePath) && !this.files.has(filePath)) {
        throw new FSError('ENOENT', filePath, 'is not a directory');
      }
      if (
        this.dirs.has(filePath) &&
        (await this.readdir(filePath)).length > 0
      ) {
        throw new FSError('ENOTEMPTY', filePath, "isn't empty");
      }
    }

    return super.rimraf(filePath);
  }

  // --------------------------------

  rmdir(...args: any): any {
    return asyncToNode(args, 3, (...p) => this._rmdir(...p));
  }
  mkdir(...args: any): any {
    return asyncToNode(args, 3, (...p) => this._mkdir(...p));
  }
  readdir(...args: any): any {
    return asyncToNode(args, 3, (...p) => super.readdir(...p));
  }
  unlink(...args: any): any {

View on GitHub (pinned to 59484858a1)

Solutions

  1. Use `{recursive: true}` to remove the dir and its contents together.
  2. Empty the directory (remove all children) before calling rmdir.
  3. Restructure so cleanup happens bottom-up.

Example fix

// before
await fs.rmdir('/a');  // still has files
// after
await fs.rimraf('/a', {recursive: true});
Defensive patterns

Strategy: validation

Validate before calling

async function removeDir(fs, p) {
  if ((await fs.readdir(p)).length > 0) await fs.rimraf(p, { recursive: true });
  else await fs.rmdir(p);
}

Try / catch

try { await fs.rmdir(p); }
catch (e) { if (e.code === 'ENOTEMPTY') await fs.rimraf(p, { recursive: true }); else throw e; }

Prevention

When it happens

Trigger: Calling `fs.rmdir('/a')` on a directory that still contains files or subdirectories, without `{recursive: true}`.

Common situations: Teardown runs before all children are removed; nested writes accumulate under the dir; ported cleanup that assumed children were already gone.

Related errors


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