Skip to content

fs: fix recursive readdir with buffer encoding - #64954

Open
canblmz1 wants to merge 1 commit into
nodejs:mainfrom
canblmz1:fix/readdir-recursive-buffer-path
Open

fs: fix recursive readdir with buffer encoding#64954
canblmz1 wants to merge 1 commit into
nodejs:mainfrom
canblmz1:fix/readdir-recursive-buffer-path

Conversation

@canblmz1

@canblmz1 canblmz1 commented Aug 2, 2026

Copy link
Copy Markdown

Description

fs.readdir(), fs.readdirSync(), and fs.promises.readdir() throw
ERR_INVALID_ARG_TYPE (or crash the process outright in the callback
case) when called with both { recursive: true } and
{ encoding: 'buffer' }. The internal recursive walk builds paths with
path.join()/path.relative(), and checks whether an entry is a
directory via a CommonJS-module-resolution-specific native stat
binding (internalModuleStat) - none of these accept Buffer
arguments, which is what entry names become once encoding: 'buffer'
is set.

const fs = require('fs');
fs.readdirSync('.', { recursive: true, encoding: 'buffer' });
// Uncaught TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument
// must be of type string. Received an instance of Buffer

Fix

  • internal/fs/utils already had an unexported join() helper that
    correctly handles string/Buffer combinations; this exports it and
    adds two more helpers alongside it: relativeToBasePath() (avoids
    needing path.relative()'s Buffer support, since the full path is
    always built by repeatedly joining onto the base path) and
    isDirectoryPath().
  • isDirectoryPath() keeps using internalModuleStat for the string
    fast path (unchanged behavior/performance for the common case), but
    falls back to the general-purpose stat binding - the same one
    fs.statSync() uses - for Buffer paths. That binding handles
    Buffers correctly at the native layer, so this also avoids a lossy
    string round-trip for non-UTF8 file names, rather than just papering
    over the reported crash.
  • lib/fs.js (handleDirents/handleFilePaths) and
    lib/internal/fs/promises.js (readdirRecursive) both had their
    own copy of this bug and are updated to use the shared helpers.

Testing

Added test/parallel/test-fs-readdir-recursive-buffer.js, covering
readdirSync, readdirSync with withFileTypes, the readdir
callback form, and fs.promises.readdir, all with
{ recursive: true, encoding: 'buffer' }.

Ran the full test/parallel/test-fs-readdir*.js suite plus a broader
test/parallel/test-fs-*.js sweep (257 files) locally on Windows
(clang-cl build) - all pass except 7 pre-existing failures unrelated
to this change (EPERM on symlinkSync due to this environment not
running elevated/without Developer Mode, verified individually).

Fixes: #58892

`fs.readdir()`, `fs.readdirSync()`, and `fs.promises.readdir()` threw
ERR_INVALID_ARG_TYPE (or crashed the process outright in the callback
case) when called with both `{ recursive: true }` and
`{ encoding: 'buffer' }`, because the internal recursive walk used
`path.join()`, `path.relative()`, and a CommonJS-module-resolution
specific native stat binding, none of which accept Buffer arguments.

Adds `relativeToBasePath()` and `isDirectoryPath()` helpers to
`internal/fs/utils`, alongside the existing (but previously
unexported) `join()` helper, all of which handle both string and
Buffer paths. The recursive readdir implementations in `lib/fs.js`
and `lib/internal/fs/promises.js` now use these instead of calling
`path`/the module-resolution stat binding directly.

`isDirectoryPath()` falls back to the general-purpose `stat` binding
(the same one `fs.statSync()` uses) for Buffer paths, so it also
handles non-UTF8 file names correctly instead of round-tripping
through a lossy string conversion.

Fixes: nodejs#58892
Signed-off-by: Can <hello@syntaxandco.com>
@nodejs-github-bot nodejs-github-bot added fs Issues and PRs related to file-system APIs and the fs module. needs-ci PRs that need a full CI run. labels Aug 2, 2026
@canblmz1
canblmz1 force-pushed the fix/readdir-recursive-buffer-path branch from 3480bbc to 50326c3 Compare September 1, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fs Issues and PRs related to file-system APIs and the fs module. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

all versions of readdir don't work in recursive mode when used with a buffer argument

2 participants