{"record":{"id":"44d66ea8cc6ff662","repo":"microsoft/typescript-go","slug":"fseventstreamcreate-returned-null","errorCode":null,"errorMessage":"FSEventStreamCreate returned NULL","messagePattern":"FSEventStreamCreate returned NULL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/fswatch/fsevents_darwin.go","lineNumber":215,"sourceCode":"\treturn nil\n}\n\n// checkWatcher mirrors the helper of the same name.\nfunc checkWatcher(w *dirWatch) error {\n\tinfo, err := os.Stat(w.physicalDir)\n\tif err != nil {\n\t\treturn &dirWatchError{err: err, dirWatch: w}\n\t}\n\tif !info.IsDir() {\n\t\treturn &dirWatchError{err: syscall.ENOTDIR, dirWatch: w}\n\t}\n\treturn nil\n}\n\nvar (\n\terrCFStringCreateNull = errors.New(\"CFStringCreate returned NULL\")\n\terrCFArrayCreateNull  = errors.New(\"CFArrayCreate returned NULL\")\n\terrStreamCreateNull   = errors.New(\"FSEventStreamCreate returned NULL\")\n\terrStreamStartFailed  = errors.New(\"error starting FSEvents stream\")\n)\n\nvar (\n\terrFSEventsUserDropped   = fmt.Errorf(\"events were dropped by the FSEvents client: %w\", ErrOverflow)\n\terrFSEventsKernelDropped = fmt.Errorf(\"events were dropped by the kernel: %w\", ErrOverflow)\n\terrFSEventsTooMany       = fmt.Errorf(\"too many events: %w\", ErrOverflow)\n)\n\nconst fseventsPathsPerStream = 512\n\ntype fseventsWatchSnapshot struct {\n\tw     *dirWatch\n\tstate *fseventsState\n}\n\nfunc (b *fsEventsBackend) activeWatchesLocked() []fseventsWatchSnapshot {\n\twatches := make([]fseventsWatchSnapshot, 0, len(b.watches))","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/fswatch/fsevents_darwin.go#L197-L233","documentation":"The final macOS setup step, FSEventStreamCreate, returned NULL, so no event stream exists for the requested paths. Beyond allocation failure, this happens when the created stream parameters are not acceptable to FSEvents (e.g. too many paths in one stream, invalid callback/context wiring), and it is reported via the errStreamCreateNull sentinel distinct from the later 'error starting FSEvents stream' (FSEventStreamStart) failure.","triggerScenarios":"Path batches exceeding what FSEvents accepts per stream (the library chunks at 512, but degenerate inputs can still fail); CF-level memory pressure; paths that are not absolute or otherwise rejected by the FSEvents API surfacing as a NULL stream.","commonSituations":"Recursive watches over enormous trees translated into many paths; macOS versions tightening FSEvents limits; sandboxed apps whose FSEvents entitlements/TCC restrict stream creation.","solutions":["Watch a single root with WithRecursive (FSEvents is natively recursive) instead of enumerating thousands of directories","Ensure all paths are absolute and exist before subscribing (see Watcher.WatchDirectory contract)","Retry after freeing memory; if the sandbox blocks FSEvents, grant Full Disk Access / file-monitoring permission or fall back to polling"],"exampleFix":"// before: one request per subdirectory\nfor _, d := range subdirs {\n    reqs = append(reqs, fswatch.WatchDirectoryRequest{Dir: d, Callback: cb})\n}\nws, err := fswatch.Default().WatchDirectories(reqs) // FSEventStreamCreate NULL\n\n// after: one recursive watch on the root\nw, err := fswatch.Default().WatchDirectory(repoRoot, cb, fswatch.WithRecursive())","handlingStrategy":"fallback","validationCode":"// All paths must be absolute and exist before requesting FSEvents streams.\nfunc validWatchRequest(r fswatch.WatchDirectoryRequest) error {\n    if !filepath.IsAbs(r.Dir) { return fmt.Errorf(\"path must be absolute: %s\", r.Dir) }\n    if info, err := os.Stat(r.Dir); err != nil || !info.IsDir() {\n        return fmt.Errorf(\"directory missing: %s\", r.Dir)\n    }\n    return nil\n}","typeGuard":"func isStreamCreateFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"FSEventStreamCreate returned NULL\")\n}","tryCatchPattern":"ws, err := fswatch.Default().WatchDirectories(reqs)\nif err != nil && isStreamCreateFailure(err) {\n    // Enumerated paths overwhelmed stream creation: one recursive root watch instead.\n    ws, err = fswatch.Default().WatchDirectory(commonRoot, cb, fswatch.WithRecursive(),\n        fswatch.WithIgnore(ignoreNonTargets(reqs)))\n}\nif err != nil { return err }","preventionTips":["On macOS use a single recursive watch per root — FSEvents recursion is the efficient path","Validate absolute, existing paths up front (the Watcher contract requires both)","Sandboxed apps: verify file-monitoring permissions; fall back to polling when FSEvents is denied"],"tags":["darwin","fsevents","watch-limits","fswatch","recursive-watch"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}