{"record":{"id":"e75fdecd0ffb08d0","repo":"microsoft/typescript-go","slug":"cfstringcreate-returned-null","errorCode":null,"errorMessage":"CFStringCreate returned NULL","messagePattern":"CFStringCreate returned NULL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/fswatch/fsevents_darwin.go","lineNumber":213,"sourceCode":"func (b *fsEventsBackend) start() error {\n\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","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/fswatch/fsevents_darwin.go#L195-L231","documentation":"On macOS, building an FSEvents stream first converts each watched path to a CFString; if CoreFoundation's CFStringCreate returns NULL (allocation failure), this sentinel error is returned and the stream is never created. It is effectively an out-of-memory condition at the CF layer.","triggerScenarios":"Creating a watch while the process/system is out of memory; requesting very many paths in one batch so the per-path CFString allocations fail; running inside memory-capped containers/CI executors on macOS runners.","commonSituations":"Watchers over huge path lists (monorepo recursive watches) on memory-pressured machines; long-running daemons with leaks that finally exhaust the heap; macOS CI hosts near their memory limit.","solutions":["Free memory / raise the container or runner memory limit before creating watches","Reduce the number and length of watched paths (watch fewer roots, prune ignores) to shrink allocations","Retry once after a pause — transient CF allocation failures usually clear when memory is released","Fall back to a polling watcher if FSEvents cannot allocate"],"exampleFix":"// before\nw, err := fswatch.Default().WatchDirectories(allRequests) // thousands of roots, CFStringCreate NULL\n\n// after: watch few roots recursively instead of listing every directory\nw, err := fswatch.Default().WatchDirectory(repoRoot, cb, fswatch.WithRecursive(),\n    fswatch.WithIgnore(ignoreHeavyDirs))","handlingStrategy":"retry","validationCode":"// Check available memory before building large FSEvents subscriptions.\nfunc memHeadroom() bool {\n    si, err := mem.VirtualMemory() // github.com/pod coconut gopsutil/v3/mem\n    if err != nil { return true }\n    return si.Available > 512*1024*1024 // require >= 512MB free\n}","typeGuard":"func isCFAllocFailure(err error) bool {\n    return err != nil && (errors.Is(err, fswatch.ErrUnavailable) == false) &&\n        (strings.Contains(err.Error(), \"CFStringCreate returned NULL\") ||\n         strings.Contains(err.Error(), \"CFArrayCreate returned NULL\"))\n}","tryCatchPattern":"w, err := watcher.WatchDirectories(reqs)\nif err != nil && isCFAllocFailure(err) {\n    time.Sleep(2 * time.Second) // let memory pressure clear\n    if w, err = watcher.WatchDirectories(reqs); isCFAllocFailure(err) {\n        return startPolling(roots(reqs)) // degrade to polling\n    }\n}\nif err != nil { return err }","preventionTips":["Prefer few recursive FSEvents watches over many enumerated paths (natively recursive on macOS)","Watch RSS in long-lived macOS daemons; restart or trim before CF allocations start failing","Free/close unused watchers — each holds CF objects that pressure the same allocator"],"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"}