microsoft/typescript-go · error
error watching %s: %w
Error message
error watching %s: %w
What it means
Synchronous error from WatchDirectory on the kqueue backend: the initial open of the watched root directory failed. subscribe() walks the tree first, then calls openForEvents (unix.Open with O_EVTONLY on darwin, O_RDONLY on other BSDs) per entry; a child-entry failure only drops that entry, but failure on the root aborts and returns this error. The %s is the directory path and the %w carries the underlying syscall errno, so errors.Is works against syscall values.
Source
Thrown at internal/fswatch/kqueue.go:484
return nil
}); err != nil {
return err
}
// Open fds, register kevents, and publish subscriptions under b.mu.
// Holding the lock for the entire block ensures that the event loop
// cannot see a partially-built entries map, and that fds are always
// tracked in fdToEntry (no leak on early return).
b.mu.Lock()
defer b.mu.Unlock()
for path, entry := range entries {
fd, err := openForEvents(entry.watchPath)
if err != nil {
if path == w.dir {
b.cleanupEntriesLocked(entries)
return &dirWatchError{
err: fmt.Errorf("error watching %s: %w", w.dir, err),
dirWatch: w,
}
}
delete(entries, path)
continue
}
var ev unix.Kevent_t
unix.SetKevent(&ev, fd, unix.EVFILT_VNODE, unix.EV_ADD|unix.EV_CLEAR|unix.EV_ENABLE)
ev.Fflags = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_EXTEND |
unix.NOTE_ATTRIB | unix.NOTE_RENAME | unix.NOTE_REVOKE
if _, err := unix.Kevent(b.kq, []unix.Kevent_t{ev}, nil, nil); err != nil {
unix.Close(fd)
if path == w.dir {
b.cleanupEntriesLocked(entries)
return &dirWatchError{
err: fmt.Errorf("error watching %s: %w", w.dir, err),
dirWatch: w,
}View on GitHub (pinned to 1bcfa18d79)
Solutions
- Verify the directory exists and is readable (unix.Access(dir, unix.R_OK)) immediately before subscribing
- Fix ownership/permissions of the target, or run the watcher with sufficient privileges
- Retry WatchDirectory with backoff when a create/delete race is possible
- Watch a stable parent directory and filter events if the target directory is short-lived
Example fix
// before
watch, err := fswatch.Kqueue().WatchDirectory(dir, cb)
if err != nil {
return err // gives up on a transient race
}
// after
var watch fswatch.Watch
for i := 0; i < 5; i++ {
var err error
watch, err = fswatch.Kqueue().WatchDirectory(dir, cb)
if err == nil {
break
}
if !errors.Is(err, syscall.ENOENT) && !errors.Is(err, syscall.EACCES) {
return err
}
time.Sleep(100 * time.Millisecond)
} Defensive patterns
Strategy: retry
Validate before calling
if _, err := os.Stat(dir); err != nil {
return err
}
if err := unix.Access(dir, unix.R_OK); err != nil {
return fmt.Errorf("directory not readable: %w", err)
} Try / catch
watch, err := fswatch.Kqueue().WatchDirectory(dir, cb)
if err != nil {
switch {
case errors.Is(err, syscall.ENOENT):
// directory vanished mid-subscribe: recreate/retry
case errors.Is(err, syscall.EACCES):
// fix permissions or privileges
default:
return err
}
} Prevention
- Check existence and readability immediately before subscribing
- Keep watch roots owned or readable by the watcher process
- Design retry logic up front: subscribe can always lose a race with deletion
- Watch stable parents for short-lived child directories
When it happens
Trigger: The directory is deleted between the tree walk and the open (race). The process lacks read permission on the directory (EACCES). The path sits on a hung or unmounted network mount (EIO/ESTALE). A macOS sandbox/Seatbelt policy denies the open.
Common situations: Caller checks os.Stat then subscribes while the directory is removed in between. CI jobs running unprivileged watch system paths such as /run or /var. NFS mounts that went away between discovery and watch.
Related errors
- %w: watched directory removed
- error opening directory: %w
- invalid handle: %w
- failed to create profile directory: %w
- failed to create CPU profile file: %w
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/523d1bbaa98ad4d4.
Report an issue: GitHub.