Skip to content

fix(ext/node): validate fs.watch boolean options#33627

Merged
bartlomieju merged 1 commit into
denoland:mainfrom
nathanwhitbot:fix/node-compat-iter57
Apr 28, 2026
Merged

fix(ext/node): validate fs.watch boolean options#33627
bartlomieju merged 1 commit into
denoland:mainfrom
nathanwhitbot:fix/node-compat-iter57

Conversation

@nathanwhitbot

Copy link
Copy Markdown
Contributor

Summary

fs.watch(path, { recursive: '1' }) previously accepted truthy non-boolean values silently. Match Node's lib/internal/fs/recursive_watch.js, which calls validateBoolean(recursive, 'options.recursive') (and the same for persistent) before starting the watcher.

Enables parallel/test-fs-watch-recursive-validate.js.

Test plan

  • parallel/test-fs-watch-recursive-validate.js passes via cargo test --test node_compat
  • Existing fs-watch* tests still pass

…booleans in `fs.watch`

`fs.watch(path, { recursive: '1' })` previously accepted the truthy non-boolean
silently. Match Node's
https://github.com/nodejs/node/blob/main/lib/internal/fs/recursive_watch.js
which calls `validateBoolean(recursive, 'options.recursive')` (and the same
for `persistent`) before starting the watcher.

Enables `parallel/test-fs-watch-recursive-validate.js`.

@nathanwhitbot nathanwhitbot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — matches Node's internal/fs/recursive_watch.js#L58-L64 for the non-native recursive path. Note Node's lib/fs.js#watch (lines 2507–2557) doesn't validate at the JS level — it relies on the C++ binding's coercion for the native path — so this PR is actually slightly stricter than Node here, which I think is fine and is what the test expects.

A couple of follow-ups worth tracking but not blocking:

  • fs.promises.watch (watchPromise in this file, line 3223) doesn't get the same validation. If the recursive-validate test only exercises sync fs.watch, that's why it passes; but a future test or user calling fsPromises.watch(path, { recursive: '1' }) would silently accept it. Worth mirroring the same two validateBoolean calls there for consistency.

  • signal and throwIfNoEntry aren't validated either (Node validates both per the linked file). Probably out of scope for the enrolled test, but they fit the same pattern when you add them later.

  • Minor: options?.recursive != null is the same as options != null && options.recursive != null — the optional chaining + != null form would shorten the two new conditionals to one line each. Stylistic only; what's there is clear too.

@fibibot fibibot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The substance is right. Verified:

  • validateBoolean is already imported at the top of fs.ts:83 and used in two other places (line 1818, 1872), so no new imports needed.
  • Both checks are guarded by options != null && options.<field> != null so passing undefined/null/no options keeps the existing fast path. Only an explicitly-set non-boolean triggers the throw.
  • Mirrors Node's lib/internal/fs/recursive_watch.js where validateBoolean(recursive, ...) and validateBoolean(persistent, ...) both run before the watcher is created. The new test (test-fs-watch-recursive-validate.js) presumably exercises both fields.

Test enrollment alphabetically positioned correctly (recursive-linux-parallel-remove < recursive-validate < ref-unref).

Holding off on APPROVE per fibibot's CI gate — only 73/n checks complete so far. Lint debug clean on all 3 platforms, but test node_compat debug is only fully green on linux-aarch64 (linux-x86_64, both macOS variants still queued or partially in-flight). Will re-confirm once the remaining node_compat debug jobs land.

@bartlomieju
bartlomieju enabled auto-merge (squash) April 28, 2026 07:18
@bartlomieju
bartlomieju merged commit 4ded364 into denoland:main Apr 28, 2026
136 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants