Skip to content

Comments

watch: fix --watch-path restart on unrelated file with --env-file#61970

Open
RajeshKumar11 wants to merge 1 commit intonodejs:mainfrom
RajeshKumar11:fix/61906-watch-path-env-file
Open

watch: fix --watch-path restart on unrelated file with --env-file#61970
RajeshKumar11 wants to merge 1 commit intonodejs:mainfrom
RajeshKumar11:fix/61906-watch-path-env-file

Conversation

@RajeshKumar11
Copy link
Contributor

Summary

  • When using --watch-path=<dir> together with --env-file=<path>, touching any file in the directory that contains the env file incorrectly triggers a restart β€” even if the changed file has nothing to do with the watched path
  • Fix: filterFile() now watches the specific file directly in 'all' mode, rather than watching its entire parent directory

Root cause

FilesWatcher has two modes:

Mode When used #onChange behaviour
'filter' No --watch-path Only fires for files in #filteredFiles
'all' --watch-path provided Fires for any change in any watched path

filterFile() in lib/internal/watch_mode/files_watcher.js:131 takes a shortcut on macOS and Windows (platforms with recursive fs.watch support): instead of setting up one watcher per file, it calls watchPath(dirname(file)) to watch the whole parent directory with a single recursive FSWatcher.

In 'filter' mode this is harmless β€” #onChange checks #filteredFiles before emitting 'changed', so only the tracked file triggers a restart.

In 'all' mode the filter check is skipped. So when watch_mode.js calls filterFile(resolve('.env')) (line 106) to watch the env file, it actually watches . (the CWD) recursively. Any fs.watch event in the CWD β€” including touch unrelated β€” then passes straight through and triggers a restart.

Fix

Add && this.#mode === 'filter' to the condition that selects the parent-directory strategy:

// Before
if (supportsRecursiveWatching) {
  this.watchPath(dirname(file));   // watches the whole directory

// After
if (supportsRecursiveWatching && this.#mode === 'filter') {
  this.watchPath(dirname(file));   // only in filter mode
} else {
  this.watchPath(file, false);     // watch the specific file
}

In 'all' mode the env file is now watched directly (watchPath(file, false)), so only changes to that exact file fire the watcher.

Tests

Two new cases added to test/parallel/test-watch-mode-files_watcher.mjs:

  1. No false trigger: filterFile() in 'all' mode + modify an unrelated file in the same directory β†’ mustNotCall asserts no 'changed' event fires
  2. Correct trigger: filterFile() in 'all' mode + modify the watched file itself β†’ 'changed' fires exactly once

Related

Ref: #61906 (reporter provided a clean minimal repro)

Fixes: #61906

@nodejs-github-bot nodejs-github-bot added the needs-ci PRs that need a full CI run. label Feb 24, 2026
@codecov
Copy link

codecov bot commented Feb 24, 2026

Codecov Report

βœ… All modified and coverable lines are covered by tests.
βœ… Project coverage is 89.77%. Comparing base (da5efc4) to head (869ff22).
⚠️ Report is 16 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #61970      +/-   ##
==========================================
+ Coverage   88.84%   89.77%   +0.93%     
==========================================
  Files         674      674              
  Lines      204957   205608     +651     
  Branches    39309    39415     +106     
==========================================
+ Hits       182087   184588    +2501     
+ Misses      15088    13270    -1818     
+ Partials     7782     7750      -32     
Files with missing lines Coverage Ξ”
lib/internal/watch_mode/files_watcher.js 91.20% <100.00%> (+3.41%) ⬆️

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

When both --watch-path=<dir> and --env-file=<path> are provided,
touching any file in the directory containing the env file incorrectly
triggered a restart, even if the changed file was unrelated to the
watched path.

Root cause: filterFile() watches dirname(file) recursively on macOS
and Windows (platforms with recursive fs.watch support). In 'filter'
mode this is harmless because #onChange only fires for files in
#filteredFiles. But in 'all' mode (used when --watch-path is set),
#onChange fires for any change in any watched path without checking
the filter, so watching the env file's parent directory caused restarts
on every file change in that directory.

Fix: only watch the parent directory in 'filter' mode. In 'all' mode,
watch the specific file directly (watchPath(file, false)) so that
changes to unrelated files in the same directory are not observed.

Fixes: nodejs#61906
@RajeshKumar11 RajeshKumar11 force-pushed the fix/61906-watch-path-env-file branch from 869ff22 to 0a288d3 Compare February 25, 2026 03:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--watch-path restarts on unrelated directory touch when --env-file is set

2 participants