diff --git a/lib/internal/fs/recursive_watch.js b/lib/internal/fs/recursive_watch.js index 7d8b12eeb93445..d312e54013cfb9 100644 --- a/lib/internal/fs/recursive_watch.js +++ b/lib/internal/fs/recursive_watch.js @@ -157,11 +157,16 @@ class FSWatcher extends EventEmitter { persistent: this.#options.persistent, }, (eventType, filename) => { const existingStat = this.#files.get(file); - const currentStats = statSync(file); + let currentStats; - this.#files.set(file, currentStats); + try { + currentStats = statSync(file); + this.#files.set(file, currentStats); + } catch { + // This happens if the file was removed + } - if (currentStats.birthtimeMs === 0 && existingStat.birthtimeMs !== 0) { + if (currentStats === undefined || (currentStats.birthtimeMs === 0 && existingStat.birthtimeMs !== 0)) { // The file is now deleted this.#files.delete(file); this.#watchers.delete(file); diff --git a/test/parallel/test-fs-watch-recursive-delete.js b/test/parallel/test-fs-watch-recursive-delete.js new file mode 100644 index 00000000000000..27d1ebcc14e005 --- /dev/null +++ b/test/parallel/test-fs-watch-recursive-delete.js @@ -0,0 +1,30 @@ +'use strict'; + +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const fs = require('fs'); + +if (common.isSunOS) + common.skip('SunOS behaves differently'); + +tmpdir.refresh(); + +fs.mkdirSync(tmpdir.resolve('./parent/child'), { recursive: true }); + +fs.writeFileSync(tmpdir.resolve('./parent/child/test.tmp'), 'test'); + +const toWatch = tmpdir.resolve('./parent'); + +const onFileUpdate = common.mustCallAtLeast((eventType, filename) => { + // We are only checking for the filename to avoid having Windows, Linux and Mac specific assertions + if (fs.readdirSync(tmpdir.resolve('./parent')).length === 0) { + watcher.close(); + } +}, 1); + +const watcher = fs.watch(toWatch, { recursive: true }, onFileUpdate); + +// We must wait a bit `fs.rm()` to let the watcher be set up properly +setTimeout(() => { + fs.rm(tmpdir.resolve('./parent/child'), { recursive: true }, common.mustCall()); +}, common.platformTimeout(500));