microsoft/typescript-go · error

unsupported fanotify metadata version: %d

Error message

unsupported fanotify metadata version: %d

What it means

A parsed fanotify event metadata record carries a version field that does not match FANOTIFY_METADATA_VERSION compiled into this binary. The kernel and userspace disagree on the ABI of the notification record, so the buffer cannot be parsed safely and the backend aborts event processing.

Source

Thrown at internal/fswatch/fanotify_linux.go:401

	for {
		n, err := unix.Read(b.fanotifyFD, buf)
		if err != nil {
			if errors.Is(err, unix.EAGAIN) || errors.Is(err, unix.EWOULDBLOCK) {
				break
			}
			return fmt.Errorf("Error reading from fanotify: %w", err)
		}
		if n == 0 {
			break
		}

		metaSize := int(unsafe.Sizeof(unix.FanotifyEventMetadata{}))
		data := buf[:n]
		for len(data) >= metaSize {
			meta := (*unix.FanotifyEventMetadata)(unsafe.Pointer(&data[0]))
			if meta.Vers != unix.FANOTIFY_METADATA_VERSION {
				return fmt.Errorf("unsupported fanotify metadata version: %d", meta.Vers)
			}
			eventLen := int(meta.Event_len)
			if eventLen < int(meta.Metadata_len) || eventLen > len(data) {
				break
			}

			// FID mode: fd should be FAN_NOFD, but close if somehow set.
			if meta.Fd >= 0 {
				_ = unix.Close(int(meta.Fd))
			}

			if meta.Mask&unix.FAN_Q_OVERFLOW != 0 {
				b.handleOverflow(watchersTouched)
				data = data[eventLen:]
				continue
			}

			infoData := data[meta.Metadata_len:eventLen]

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Rebuild/update the binary so its x/sys/unix fanotify constants match the running kernel (>= 5.1 with FID reporting)
  2. Run on a mainstream, current kernel where the fanotify ABI matches FANOTIFY_METADATA_VERSION
  3. Fall back to the inotify backend for that environment

Example fix

// before
w, err := fswatch.Default().WatchDirectory(dir, cb) // metadata version mismatch on old custom kernel

// after: pin a backend with a stable ABI on this host
w, err := fswatch.Inotify().WatchDirectory(dir, cb, fswatch.WithRecursive())
Defensive patterns

Strategy: fallback

Validate before calling

// Report the ABI mismatch precisely instead of failing vaguely.
func fanotifyAbiOK() error {
    var u unix.Utsname
    if unix.Uname(&u) == nil {
        v := strings.TrimPrefix(unix.ByteSliceToString(u.Release[:]), "")
        if semverLess(v, "5.1.0") {
            return fmt.Errorf("kernel %s lacks FID fanotify ABI", v)
        }
    }
    return nil
}

Type guard

func isMetadataVersionMismatch(err error) bool {
    return err != nil && strings.Contains(err.Error(), "unsupported fanotify metadata version")
}

Try / catch

w, err := fswatch.Default().WatchDirectory(dir, cb, opts...)
if err != nil && isMetadataVersionMismatch(err) {
    // Kernel/binary ABI mismatch: switch to a backend with a stable ABI.
    w, err = fswatch.Inotify().WatchDirectory(dir, cb, opts...)
}
if err != nil { return err }

Prevention

When it happens

Trigger: Running a binary built against one kernel header set on a kernel with a different fanotify metadata ABI (essentially only possible across very old/mismatched kernels or patched kernels); golang.org/x/sys/unix constants out of sync with the running kernel.

Common situations: Extremely rare in practice; would surface after OS downgrades to pre-FID fanotify, custom/vendor kernels, or running under syscall-shimming VMs that synthesize fanotify responses.

Related errors


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