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

  1. Check errors.Is(err, fswatch.ErrWatchTerminated) in every callback and call Close() on the Watch
  2. Re-subscribe once the target exists again (poll for existence, then WatchDirectory)
  3. Watch a stable parent and filter child events for directories with delete/recreate cycles
  4. 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

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


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/5781284a46f9e197. Report an issue: GitHub.