docker/compose · error

notify.Add(%q): %w

Error message

notify.Add(%q): %w

What it means

In naiveNotify.Add (the non-recursive fallback watcher used when fsnotify lacks recursive support), each candidate path is stat'ed before a watch is added. A stat error that is neither nil nor IsNotExist — permission denial or I/O error — is wrapped with the path name. This mirrors greatestExistingAncestor's logic but happens at registration time.

Source

Thrown at pkg/watch/watcher_naive.go:82

	}

	pathsToWatch := []string{}
	for path := range d.notifyList {
		pathsToWatch = append(pathsToWatch, path)
	}

	pathsToWatch, err := greatestExistingAncestors(pathsToWatch)
	if err != nil {
		return err
	}
	if d.isWatcherRecursive {
		pathsToWatch = pathutil.EncompassingPaths(pathsToWatch)
	}

	for _, name := range pathsToWatch {
		fi, err := os.Stat(name)
		if err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("notify.Add(%q): %w", name, err)
		}

		// if it's a file that doesn't exist,
		// we should have caught that above, let's just skip it.
		if os.IsNotExist(err) {
			continue
		}

		if fi.IsDir() {
			err = d.watchRecursively(name)
			if err != nil {
				return fmt.Errorf("notify.Add(%q): %w", name, err)
			}
		} else {
			err = d.addWatch(filepath.Dir(name))
			if err != nil {
				return fmt.Errorf("notify.Add(%q): %w", filepath.Dir(name), err)
			}

View on GitHub (pinned to ddc4b044b6)

Solutions

  1. Check the path from the message with ls -ld and grant the current user read/search permission on it.
  2. Remove the inaccessible path from the watch set (fix develop.watch entries) if it is not essential.
  3. Repair the underlying mount/filesystem if stat fails with an I/O error.
Defensive patterns

Strategy: validation

Validate before calling

// verify each watch path is stat-able (or confirmed absent) up front
for _, p := range paths {
    if _, err := os.Stat(p); err != nil && !os.IsNotExist(err) {
        return fmt.Errorf("path %q not accessible: %w", p, err)
    }
}

Try / catch

if err != nil {
    var pathErr *os.PathError
    if errors.As(err, &pathErr) && os.IsPermission(pathErr) {
        // report pathErr.Path and advise chmod/chown
    }
    return err // non-permission stat failures are environment faults
}

Prevention

When it happens

Trigger: d.Add(paths) hitting a path whose stat fails with EACCES/EIO while the naive (non-fsevents, non-recursive fsnotify) watcher registers watches. NotNotExist errors are deliberately skipped (missing files were resolved earlier), so only real stat failures land here.

Common situations: Watch roots under directories with restrictive permissions; paths on failing disks or stale network mounts; Linux systems without recursive inotify support taking this code path (e.g. older kernels or non-Linux non-macOS platforms).

Related errors


AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15). Data as JSON: /api/errors/37f8f55770452f60. Report an issue: GitHub.