Skip to content

fs: opendirSync() leaks directory handle on error #58854

@LiviaMedeiros

Description

@LiviaMedeiros

Version

v25.0.0-pre

Platform

Linux tumba 6.15.3-gentoo-yuran #1 SMP Sat Jun 21 21:02:19 +08 2025 x86_64 Intel(R) Core(TM)2 Quad CPU Q8200 @ 2.33GHz GenuineIntel GNU/Linux

Subsystem

fs

What steps will reproduce the bug?

test.mjs script:

import fs from 'node:fs';
{
  let dir;
  try {
    dir = fs.opendirSync(import.meta.dirname, { bufferSize: Infinity });
    console.log('successfully got', dir);
  } catch(e) {
    console.log('dir is:', dir, 'error is:', e);
  } finally {
    dir?.closeSync();
  }
}
globalThis.gc();
setImmediate(() => {});

Run it with expose GC flag:

$ node --expose-gc test.mjs

How often does it reproduce? Is there a required condition?

Always, assuming GC runs.

What is the expected behavior? Why is that the expected behavior?

The "successfully got" should not be printed.
The catched error must be ERR_OUT_OF_RANGE because of bad bufferSize.
The dir should be either:

  • An instance of fs.Dir that we can closeSync() gracefully
  • undefined assuming opendirSync internally did cleanup

And most importantly, this code must not emit any warnings.

What do you see instead?

dir is: undefined error is: RangeError [ERR_OUT_OF_RANGE]: The value of "options.bufferSize" is out of range. It must be an integer. Received Infinity
    at new Dir (node:internal/fs/dir:61:5)
    at Object.opendirSync (node:internal/fs/dir:351:10)
    at file:///tmp/test.mjs:5:14
    at ModuleJob.run (node:internal/modules/esm/module_job:372:25)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:665:26)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:99:5) {
  code: 'ERR_OUT_OF_RANGE'
}
(node:8286) Warning: Closing directory handle on garbage collection
(Use `node --trace-warnings ...` to show where the warning was created)

Which means: dir stays undefined so we can not do anything about it, but the internal directory handle remains open until GC hunts it down.

Additional information

I haven't checked if fsPromises.opendir nor fs.opendir have similar problem but most likely they do.

I think this can be fixed on JS side, the patch is WIP.

Metadata

Metadata

Assignees

No one assigned

    Labels

    fsIssues and PRs related to the fs subsystem / file system.

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions