microsoft/typescript-go · error
fswatch: watch terminated
Error message
fswatch: watch terminated
What it means
Exported terminal sentinel: the watch is dead and delivers no further events. It is produced when the watched directory is deleted (backends wrap 'watched directory removed' with it), the descriptor is revoked, or a backend hits an unrecoverable error routed through handleWatcherError, which wraps any dirWatchError with it. Delivered on the callback; the documented recovery is to handle it and re-subscribe if the target returns, and to call Close to release state.
Source
Thrown at internal/fswatch/watcher.go:37
// errRootPath is returned by WatchFile when the supplied path is a
// filesystem root with no parent directory to watch.
var errRootPath = errors.New("fswatch: cannot watch a root path")
// errNotAbsolute is returned by [Watcher.WatchDirectory] and
// [Watcher.WatchFile] when the supplied path is not absolute.
var errNotAbsolute = errors.New("fswatch: path must be absolute")
// ErrOverflow indicates that the kernel event queue overflowed and
// some filesystem changes were missed. The watch remains
// active; further events will continue to be delivered. Callers
// should treat this as a signal to rescan the watched directory.
var ErrOverflow = errors.New("fswatch: event overflow; some changes were missed")
// ErrWatchTerminated indicates that the watch was terminated due to
// an unrecoverable error (e.g. the watched directory was deleted or
// the watch descriptor was revoked). No further events will be
// delivered. Call Close to release remaining state.
var ErrWatchTerminated = errors.New("fswatch: watch terminated")
// ErrUnavailable indicates that a requested watcher is not
// available on the current platform.
var ErrUnavailable = errors.New("fswatch: watcher not available on this platform")
// ErrFilesystemUnsupported indicates that the active watcher backend cannot
// operate on the target filesystem, even though the backend is available on
// the current platform. This happens, for example, with the fanotify backend
// on filesystems that do not support FID-based watching: name_to_handle_at
// returning EOPNOTSUPP (some Docker bind mounts backed by virtiofs, gRPC FUSE,
// or overlayfs) or fanotify_mark returning ENODEV (e.g. NTFS mounted via
// fuseblk).
var ErrFilesystemUnsupported = errors.New("fswatch: watcher backend unsupported on this filesystem")
// Watcher represents a filesystem watching implementation.
// Use one of the constructor functions ([Inotify], [FSEvents], [Kqueue],
// [Windows]) to obtain a value, or [Default] for the platform default.
//View on GitHub (pinned to 1bcfa18d79)
Solutions
- Check errors.Is(err, fswatch.ErrWatchTerminated) in every callback and call Close() on the Watch
- Re-subscribe once the target exists again (poll for existence, then WatchDirectory)
- Watch a stable parent and filter child events for directories with delete/recreate cycles
- Escalate to a polling watcher for paths where re-watching is unreliable
Example fix
// before
watch, _ := w.WatchDirectory(dir, cb) // callback ignores err
// after
watch, _ := w.WatchDirectory(dir, func(events []fswatch.Event, err error) {
if errors.Is(err, fswatch.ErrWatchTerminated) {
watch.Close()
go resubscribeWhenDirExists(dir)
return
}
cb(events, err)
}) Defensive patterns
Strategy: try-catch
Type guard
func isWatchTerminated(err error) bool {
return errors.Is(err, fswatch.ErrWatchTerminated)
} Try / catch
func(events []fswatch.Event, err error) {
if errors.Is(err, fswatch.ErrWatchTerminated) {
watch.Close()
go resubscribeWhenTargetExists(target)
return
}
apply(events)
} Prevention
- Close terminated watches so per-directory state is released
- Keep state rebuildable via full rescan for every watch you own
- Prefer watching stable ancestors over delete/recreate targets
- Remember WatchFile has no polling fallback: parent deletion is terminal
When it happens
Trigger: Deletion or rename-away of the watched root on any backend. Revoked handles (kqueue NOTE_REVOKE, for example an unmounted filesystem). Fatal Windows backend errors such as GetOverlappedResult failures or unknown completion errors.
Common situations: Build clean steps removing output directories. Removable media or network mounts unmounted under the watch. Container filesystems torn down at shutdown. WatchFile on a file whose parent directory is removed (no automatic recovery, unlike polling).
Related errors
- %w: watched directory removed
- %w: %w
- failed to read changes
- _submodules/TypeScript does not exist; try running `git subm
- Expected version in .custom-gcl.yml
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/5781284a46f9e197.
Report an issue: GitHub.