{"record":{"id":"523d1bbaa98ad4d4","repo":"microsoft/typescript-go","slug":"error-watching-s-w","errorCode":null,"errorMessage":"error watching %s: %w","messagePattern":"error watching (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/fswatch/kqueue.go","lineNumber":484,"sourceCode":"\t\treturn nil\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\t// Open fds, register kevents, and publish subscriptions under b.mu.\n\t// Holding the lock for the entire block ensures that the event loop\n\t// cannot see a partially-built entries map, and that fds are always\n\t// tracked in fdToEntry (no leak on early return).\n\tb.mu.Lock()\n\tdefer b.mu.Unlock()\n\n\tfor path, entry := range entries {\n\t\tfd, err := openForEvents(entry.watchPath)\n\t\tif err != nil {\n\t\t\tif path == w.dir {\n\t\t\t\tb.cleanupEntriesLocked(entries)\n\t\t\t\treturn &dirWatchError{\n\t\t\t\t\terr:      fmt.Errorf(\"error watching %s: %w\", w.dir, err),\n\t\t\t\t\tdirWatch: w,\n\t\t\t\t}\n\t\t\t}\n\t\t\tdelete(entries, path)\n\t\t\tcontinue\n\t\t}\n\t\tvar ev unix.Kevent_t\n\t\tunix.SetKevent(&ev, fd, unix.EVFILT_VNODE, unix.EV_ADD|unix.EV_CLEAR|unix.EV_ENABLE)\n\t\tev.Fflags = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_EXTEND |\n\t\t\tunix.NOTE_ATTRIB | unix.NOTE_RENAME | unix.NOTE_REVOKE\n\t\tif _, err := unix.Kevent(b.kq, []unix.Kevent_t{ev}, nil, nil); err != nil {\n\t\t\tunix.Close(fd)\n\t\t\tif path == w.dir {\n\t\t\t\tb.cleanupEntriesLocked(entries)\n\t\t\t\treturn &dirWatchError{\n\t\t\t\t\terr:      fmt.Errorf(\"error watching %s: %w\", w.dir, err),\n\t\t\t\t\tdirWatch: w,\n\t\t\t\t}","sourceCodeStart":466,"sourceCodeEnd":502,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/fswatch/kqueue.go#L466-L502","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nwatch, err := fswatch.Kqueue().WatchDirectory(dir, cb)\nif err != nil {\n    return err // gives up on a transient race\n}\n\n// after\nvar watch fswatch.Watch\nfor i := 0; i < 5; i++ {\n    var err error\n    watch, err = fswatch.Kqueue().WatchDirectory(dir, cb)\n    if err == nil {\n        break\n    }\n    if !errors.Is(err, syscall.ENOENT) && !errors.Is(err, syscall.EACCES) {\n        return err\n    }\n    time.Sleep(100 * time.Millisecond)\n}","handlingStrategy":"retry","validationCode":"if _, err := os.Stat(dir); err != nil {\n    return err\n}\nif err := unix.Access(dir, unix.R_OK); err != nil {\n    return fmt.Errorf(\"directory not readable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"watch, err := fswatch.Kqueue().WatchDirectory(dir, cb)\nif err != nil {\n    switch {\n    case errors.Is(err, syscall.ENOENT):\n        // directory vanished mid-subscribe: recreate/retry\n    case errors.Is(err, syscall.EACCES):\n        // fix permissions or privileges\n    default:\n        return err\n    }\n}","preventionTips":["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"],"tags":["kqueue","darwin","bsd","permissions","race-condition","filesystem"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}