Skip to content

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

Open
@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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions