microsoft/typescript-go · error
name_to_handle_at: %w
Error message
name_to_handle_at: %w
What it means
After successfully fanotify-marking a directory, the backend needs a stable handle (name_to_handle_at) to build the FID subscription key mapping events back to watches. If the syscall fails, the mark is rolled back and the error is wrapped; EOPNOTSUPP/ENOTSUP/ENODEV (filesystems without exportable file handles) are additionally wrapped in ErrFilesystemUnsupported.
Source
Thrown at internal/fswatch/fanotify_linux.go:359
}
}
return nil
}); err != nil {
_ = b.closeWatch(w)
return err
}
return nil
}
func (b *fanotifyBackend) markDir(w *dirWatch, path string, markPath string) error {
if err := unix.FanotifyMark(b.fanotifyFD, fanotifyMarkAddFlags, b.markMask, unix.AT_FDCWD, markPath); err != nil {
return maybeWrapUnsupportedFilesystem(err)
}
handle, _, err := unix.NameToHandleAt(unix.AT_FDCWD, markPath, 0)
if err != nil {
// Unmark since we can't track this directory without a handle.
_ = unix.FanotifyMark(b.fanotifyFD, unix.FAN_MARK_REMOVE|unix.FAN_MARK_ONLYDIR, b.markMask, unix.AT_FDCWD, markPath)
return maybeWrapUnsupportedFilesystem(fmt.Errorf("name_to_handle_at: %w", err))
}
var st unix.Statfs_t
if err := unix.Statfs(markPath, &st); err != nil {
_ = unix.FanotifyMark(b.fanotifyFD, unix.FAN_MARK_REMOVE|unix.FAN_MARK_ONLYDIR, b.markMask, unix.AT_FDCWD, markPath)
return fmt.Errorf("statfs: %w", err)
}
key := makeFanotifyHandleKey(st.Fsid.Val, handle.Type(), handle.Bytes())
sub := &fanotifySubscription{path: path, watchPath: markPath, dirWatch: w, key: key}
b.subscriptions[key] = append(b.subscriptions[key], sub)
return nil
}
func maybeWrapUnsupportedFilesystem(err error) error {
if errors.Is(err, unix.EOPNOTSUPP) || errors.Is(err, unix.ENOTSUP) || errors.Is(err, unix.ENODEV) {
return fmt.Errorf("%w: %w", err, ErrFilesystemUnsupported)
}
return err
}View on GitHub (pinned to 1bcfa18d79)
Solutions
- Detect via errors.Is(err, fswatch.ErrFilesystemUnsupported) and use a different backend (inotify or polling) for that path
- Move the watched tree to a native filesystem (e.g. Linux ext4 volume instead of the shared mount)
- Reconfigure the sharing layer to a filesystem that supports file handles (e.g. NFS with exportfs support, native disk image)
Example fix
// before
w, err := fswatch.Default().WatchDirectory("/mnt/host_src", cb, fswatch.WithRecursive()) // name_to_handle_at EOPNOTSUPP
// after
w, err := fswatch.Default().WatchDirectory("/mnt/host_src", cb, fswatch.WithRecursive())
if err != nil && errors.Is(err, fswatch.ErrFilesystemUnsupported) {
w, err = fswatch.Inotify().WatchDirectory("/mnt/host_src", cb, fswatch.WithRecursive())
} Defensive patterns
Strategy: fallback
Validate before calling
// Cheap pre-flight: statfs the target and reject known-unsupported FUSE types.
func fsSupportsHandles(path string) bool {
var st unix.Statfs_t
if err := unix.Statfs(path, &st); err != nil { return false }
// virtiofs / fuse / fuseblk magic numbers
magic := uint64(st.Type) & 0xFFFF_FFFF_FFFF_FFFF
switch magic {
case 0x73757245 /* fuse */, 0x65735546 /* v9fs */, 0x564c4f42 /* virtiofs */:
return false
}
return true
} Type guard
func isUnsupportedFS(err error) bool {
return err != nil && errors.Is(err, fswatch.ErrFilesystemUnsupported)
} Try / catch
w, err := fswatch.Default().WatchDirectory(dir, cb, opts...)
if err != nil && isUnsupportedFS(err) {
// name_to_handle_at failed: this fs cannot do FID watching. Use inotify or poll.
if w, err = fswatch.Inotify().WatchDirectory(dir, cb, opts...); err != nil {
return startPolling(dir, cb)
}
} Prevention
- On macOS Docker/Podman, keep source on the VM's native fs or plan an inotify/poll fallback for bind mounts
- Check errors.Is(err, fswatch.ErrFilesystemUnsupported) — the library defines it exactly for this branch
- Don't retry the same backend on the same mount: EOPNOTSUPP is permanent for that filesystem
When it happens
Trigger: Watching directories on filesystems that do not support file handles: Docker bind mounts over virtiofs, gRPC FUSE (macOS file sharing), some NFS configs, overlayfs — EOPNOTSUPP; NTFS via fuseblk — ENODEV; EPERM where CAP_DAC_READ_SEARCH is required to open handles on some filesystems.
Common situations: Dev containers on macOS Docker Desktop / Podman machine sharing the workspace via FUSE; WSL2 mounts; CI runners checking out to FUSE-backed volumes.
Related errors
- fswatch: watcher backend unsupported on this filesystem
- unable to open pipe: %w
- unable to initialize fanotify: %w
- unable to poll: %w
- fanotify_mark on '%s' failed: %w
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/cc8571514ee82aec.
Report an issue: GitHub.