Skip to content

fs: validate the callback passed to fs.rm() - #65588

Open
bitpshr wants to merge 1 commit into
nodejs:mainfrom
bitpshr:fs/rm-validate-callback
Open

fs: validate the callback passed to fs.rm()#65588
bitpshr wants to merge 1 commit into
nodejs:mainfrom
bitpshr:fs/rm-validate-callback

Conversation

@bitpshr

@bitpshr bitpshr commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Refs: #65578

Every other callback based fs API runs its callback through makeCallback(), so a missing or non-function callback is reported synchronously as ERR_INVALID_ARG_TYPE. fs.rm() skipped that step:

$ node -e 'require("fs").rmdir("/tmp/x", {})'
TypeError [ERR_INVALID_ARG_TYPE]: The "cb" argument must be of type function.

$ node -e 'require("fs").rm("/tmp/x", { force: true })'
TypeError: callback is not a function
    at CB (node:internal/fs/rimraf:53:5)

The second one is thrown from an async completion handler, so it cannot be caught, and it only happens after the removal has already run. On my machine the directory was gone by the time the process died. Adding the makeCallback() call brings rm() in line with rmdir() and unlink() and means nothing is deleted when the call was malformed.

I found this while looking at #65578. That issue is mostly about fs.rm silently failing on non-ASCII paths on Windows, which I have no way to reproduce and which this does not address. But one row of the reporter's table is the crash above, and that reproduces anywhere with plain ASCII paths, so it seemed worth separating out.

I put the makeCallback() call after the vfs handler check because that is where unlink() and rmdir() put theirs. That leaves the vfs branch passing an unvalidated callback to vfsVoid(), but that is equally true of the other two today, so fixing it only here felt like the wrong shape. Happy to do it across all of them in a follow-up if that is preferred.

Every other callback based fs API runs its callback through
makeCallback(), so a missing or non-function callback is reported
synchronously as ERR_INVALID_ARG_TYPE. fs.rm() skipped that step, so
the bad callback was not noticed until rimraf tried to invoke it, by
which point the removal had already happened and the resulting
"callback is not a function" TypeError was thrown from an async
completion handler where it could not be caught.

Refs: nodejs#65578
Signed-off-by: Paul Bouchon <mail@bitpshr.net>
@nodejs-github-bot nodejs-github-bot added fs Issues and PRs related to the fs subsystem / file system. needs-ci PRs that need a full CI run. labels Aug 27, 2026
@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.07%. Comparing base (9baabd4) to head (04fe79a).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #65588      +/-   ##
==========================================
- Coverage   90.07%   90.07%   -0.01%     
==========================================
  Files         751      751              
  Lines      254875   254876       +1     
  Branches    48108    48116       +8     
==========================================
- Hits       229579   229568      -11     
- Misses      16466    16477      +11     
- Partials     8830     8831       +1     
Files with missing lines Coverage Δ
lib/fs.js 98.43% <100.00%> (+<0.01%) ⬆️

... and 30 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.

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 the fs subsystem / file system. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants