{"record":{"id":"ad499ddaa8a84a7b","repo":"microsoft/typescript-go","slug":"cfarraycreate-returned-null","errorCode":null,"errorMessage":"CFArrayCreate returned NULL","messagePattern":"CFArrayCreate returned NULL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/fswatch/fsevents_darwin.go","lineNumber":214,"sourceCode":"\tb.notifyStarted()\n\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 {","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/fswatch/fsevents_darwin.go#L196-L232","documentation":"On macOS, after the per-path CFStrings are built, FSEvents setup gathers them into a CFArray; if CFArrayCreate returns NULL (again an allocation failure at the CoreFoundation layer), stream creation aborts with this sentinel. The library batches at most 512 paths per stream (fseventsPathsPerStream), so hitting this means memory exhaustion rather than a path-count limit.","triggerScenarios":"Watching enough paths that even the batched CFArray allocation fails under memory pressure; heap fragmentation in a long-lived process; system-wide memory pressure on macOS causing CF allocations to fail.","commonSituations":"Recursive watchers materializing many directory entries; daemons that leaked memory over days; CI jobs running many watchers in parallel on one runner.","solutions":["Restart or trim the process to release memory, then recreate the watcher","Lower the number of simultaneously watched directories; rely on WithRecursive rather than enumerating subtrees","Retry stream creation with backoff after freeing resources"],"exampleFix":"// before\nws, err := fswatch.Default().WatchDirectories(requests) // CFArrayCreate NULL under pressure\n\n// after: fewer, broader watches + retry\nw, err := fswatch.Default().WatchDirectory(root, cb, fswatch.WithRecursive())\nif err != nil && isCFAllocFailure(err) {\n    time.Sleep(2 * time.Second) // let memory settle\n    w, err = fswatch.Default().WatchDirectory(root, cb, fswatch.WithRecursive())\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isCFAllocFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"CFArrayCreate returned NULL\")\n}","tryCatchPattern":"ws, err := watcher.WatchDirectories(reqs)\nif err != nil && isCFAllocFailure(err) {\n    runtime.GC()                  // release Go-side garbage holding CF memory\n    time.Sleep(time.Second)\n    ws, err = watcher.WatchDirectories(reqs)\n    if err != nil && isCFAllocFailure(err) {\n        return startPolling(roots(reqs))\n    }\n}\nif err != nil { return err }","preventionTips":["Keep the path count per WatchDirectories batch modest; let WithRecursive cover the tree","Shut down and recreate watchers after long uptime instead of accumulating subscriptions","Investigate leaks with Instruments/heap profiles when this error appears in steady state"],"tags":["darwin","fsevents","corefoundation","out-of-memory","fswatch"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}