Skip to content

fs: support Buffer paths in cp() and cpSync() - #65713

Open
HuzaifaAbdulRehman wants to merge 1 commit into
nodejs:mainfrom
HuzaifaAbdulRehman:fix/58634-cp-buffer-paths-filter
Open

fs: support Buffer paths in cp() and cpSync()#65713
HuzaifaAbdulRehman wants to merge 1 commit into
nodejs:mainfrom
HuzaifaAbdulRehman:fix/58634-cp-buffer-paths-filter

Conversation

@HuzaifaAbdulRehman

Copy link
Copy Markdown

What breaks

fs.cpSync() with a filter, and fs.promises.cp(), throw ERR_INVALID_ARG_TYPE when src or dest is a Buffer, though Buffer paths are accepted elsewhere in fs (they address non-UTF-8 byte file names on POSIX).

const { cpSync, mkdirSync } = require('node:fs');
mkdirSync('a/c', { recursive: true });
cpSync(Buffer.from('a'), Buffer.from('b'), { recursive: true, filter: () => true });
// TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string.
//     at join (node:path)
//     at copyDir (node:internal/fs/cp/cp-sync)

Root cause

The recursive walk builds child paths with path.join(src, name), and the async path also runs path.resolve() / path.dirname() in its structural checks. All reject a Buffer. cpSync without a filter avoids it (that branch runs in C++); cp.promises hits it in isSrcSubdir before copying.

The change

joinPath joins entries onto Buffer paths by concatenating bytes, and copyDir reads entries with encoding: 'buffer' for Buffer sources, so non-UTF-8 names survive rather than being mangled. toPathString decodes to a string only for the subdirectory and parent-directory checks; the copy keeps the Buffers.

String paths over a non-UTF-8-named entry stay unchanged (a string cannot carry those bytes) and remain a known issue, nearer #58869.

Tests

Promotes the two #58634 known-issue tests into test/parallel/ and adds a Linux-only byte-fidelity test (a Shift-JIS file name copied intact through Buffer paths).

Fixes: #58634

@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 Sep 1, 2026
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.71930% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.04%. Comparing base (e68a93a) to head (cb6e436).
⚠️ Report is 23 commits behind head on main.

Files with missing lines Patch % Lines
lib/internal/fs/cp/cp.js 85.71% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #65713      +/-   ##
==========================================
- Coverage   90.06%   90.04%   -0.02%     
==========================================
  Files         754      754              
  Lines      256360   256438      +78     
  Branches    48486    48508      +22     
==========================================
+ Hits       230891   230919      +28     
- Misses      16584    16629      +45     
- Partials     8885     8890       +5     
Files with missing lines Coverage Δ
lib/internal/fs/cp/cp-sync.js 70.91% <100.00%> (+0.35%) ⬆️
lib/internal/fs/cp/cp.js 88.88% <85.71%> (-0.14%) ⬇️

... and 43 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@HuzaifaAbdulRehman
HuzaifaAbdulRehman force-pushed the fix/58634-cp-buffer-paths-filter branch from cb6e436 to 258a798 Compare September 2, 2026 09:16
`fs.cpSync()` with a filter, and `fs.promises.cp()`, threw
`ERR_INVALID_ARG_TYPE` when `src` or `dest` was a Buffer. The recursive
directory walk passed the Buffer paths to `path.join()`, and the async
path additionally to `path.resolve()` and `path.dirname()`, all of
which only accept strings. The sync path only reached this on the
filter branch because the no-filter branch runs entirely in C++.

Join directory entries onto Buffer paths by concatenating bytes, read
entries with `encoding: 'buffer'` so non-UTF-8 byte file names on POSIX
are preserved, and decode Buffer paths to strings only for the
structural subdirectory and parent-directory checks.

Fixes: nodejs#58634
Assisted-by: Claude Code
Signed-off-by: Huzaifa Abdul Rehman <huzaifarehman897@gmail.com>
@HuzaifaAbdulRehman
HuzaifaAbdulRehman force-pushed the fix/58634-cp-buffer-paths-filter branch from 258a798 to 004d3c3 Compare September 2, 2026 09:17
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.

fs.cpSync / fs.cp / fs.promises.cp fails when src/dest args are Buffer

2 participants