microsoft/typescript-go · error

FSEventStreamCreate returned NULL

Error message

FSEventStreamCreate returned NULL

What it means

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.

Source

Thrown at internal/fswatch/fsevents_darwin.go:215

	return nil
}

// checkWatcher mirrors the helper of the same name.
func checkWatcher(w *dirWatch) error {
	info, err := os.Stat(w.physicalDir)
	if err != nil {
		return &dirWatchError{err: err, dirWatch: w}
	}
	if !info.IsDir() {
		return &dirWatchError{err: syscall.ENOTDIR, dirWatch: w}
	}
	return nil
}

var (
	errCFStringCreateNull = errors.New("CFStringCreate returned NULL")
	errCFArrayCreateNull  = errors.New("CFArrayCreate returned NULL")
	errStreamCreateNull   = errors.New("FSEventStreamCreate returned NULL")
	errStreamStartFailed  = errors.New("error starting FSEvents stream")
)

var (
	errFSEventsUserDropped   = fmt.Errorf("events were dropped by the FSEvents client: %w", ErrOverflow)
	errFSEventsKernelDropped = fmt.Errorf("events were dropped by the kernel: %w", ErrOverflow)
	errFSEventsTooMany       = fmt.Errorf("too many events: %w", ErrOverflow)
)

const fseventsPathsPerStream = 512

type fseventsWatchSnapshot struct {
	w     *dirWatch
	state *fseventsState
}

func (b *fsEventsBackend) activeWatchesLocked() []fseventsWatchSnapshot {
	watches := make([]fseventsWatchSnapshot, 0, len(b.watches))

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Watch a single root with WithRecursive (FSEvents is natively recursive) instead of enumerating thousands of directories
  2. Ensure all paths are absolute and exist before subscribing (see Watcher.WatchDirectory contract)
  3. Retry after freeing memory; if the sandbox blocks FSEvents, grant Full Disk Access / file-monitoring permission or fall back to polling

Example fix

// before: one request per subdirectory
for _, d := range subdirs {
    reqs = append(reqs, fswatch.WatchDirectoryRequest{Dir: d, Callback: cb})
}
ws, err := fswatch.Default().WatchDirectories(reqs) // FSEventStreamCreate NULL

// after: one recursive watch on the root
w, err := fswatch.Default().WatchDirectory(repoRoot, cb, fswatch.WithRecursive())
Defensive patterns

Strategy: fallback

Validate before calling

// All paths must be absolute and exist before requesting FSEvents streams.
func validWatchRequest(r fswatch.WatchDirectoryRequest) error {
    if !filepath.IsAbs(r.Dir) { return fmt.Errorf("path must be absolute: %s", r.Dir) }
    if info, err := os.Stat(r.Dir); err != nil || !info.IsDir() {
        return fmt.Errorf("directory missing: %s", r.Dir)
    }
    return nil
}

Type guard

func isStreamCreateFailure(err error) bool {
    return err != nil && strings.Contains(err.Error(), "FSEventStreamCreate returned NULL")
}

Try / catch

ws, err := fswatch.Default().WatchDirectories(reqs)
if err != nil && isStreamCreateFailure(err) {
    // Enumerated paths overwhelmed stream creation: one recursive root watch instead.
    ws, err = fswatch.Default().WatchDirectory(commonRoot, cb, fswatch.WithRecursive(),
        fswatch.WithIgnore(ignoreNonTargets(reqs)))
}
if err != nil { return err }

Prevention

When it happens

Trigger: 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.

Common situations: Recursive watches over enormous trees translated into many paths; macOS versions tightening FSEvents limits; sandboxed apps whose FSEvents entitlements/TCC restrict stream creation.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/44d66ea8cc6ff662. Report an issue: GitHub.