GoogleContainerTools/skaffold · error

unable to stat file %q: %w

Error message

unable to stat file %q: %w

What it means

Skaffold's file monitor builds a map of file paths to modification times by calling os.Stat on each registered dependency. If Stat fails for a reason other than 'file does not exist' (missing files are deliberately skipped), the walk cannot proceed reliably, so it aborts with this wrapped error naming the path and the underlying cause.

Source

Thrown at pkg/skaffold/filemon/changes.go:47

// FileMap is a map of filename to modification times.
type FileMap map[string]time.Time

// Stat returns the modification times for a list of files.
func Stat(deps func() ([]string, error)) (FileMap, error) {
	state := FileMap{}
	paths, err := deps()
	if err != nil {
		return state, fmt.Errorf("listing files: %w", err)
	}
	for _, path := range paths {
		stat, err := os.Stat(path)
		if err != nil {
			if os.IsNotExist(err) {
				log.Entry(context.TODO()).Debugf("could not stat dependency: %s", err)
				continue // Ignore files that don't exist
			}
			return nil, fmt.Errorf("unable to stat file %q: %w", path, err)
		}
		state[path] = stat.ModTime()
	}

	return state, nil
}

type Events struct {
	Added    []string
	Modified []string
	Deleted  []string
}

func (e Events) HasChanged() bool {
	return len(e.Added) != 0 || len(e.Deleted) != 0 || len(e.Modified) != 0
}

func (e *Events) String() string {

View on GitHub (pinned to a1189de023)

Solutions

  1. Fix the underlying os.Stat error shown in the wrapped cause (permissions, stale mount, I/O).
  2. Check that the watched path exists and all parent directories grant read+execute to the user running Skaffold.
  3. Remove or correct the offending dependency/glob in skaffold.yaml if it points at a pseudo-filesystem or unstable path.
  4. Re-run as a user with sufficient permissions, or remount the volume.

Example fix

// before (watching a root-owned dir without perms)
watchedPaths:
  - /var/run/secrets/...
// after (watch an accessible copy or fix perms)
sudo chmod o+rx /var/run/secrets
# or point build artifacts to a user-writable dir
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat(path); err != nil && !os.IsNotExist(err) {
    return fmt.Errorf("path %q is not statable: %w", path, err)
}

Type guard

func isNotExistErr(err error) bool {
    return errors.Is(err, os.ErrNotExist)
}

Try / catch

state, err := Stat(paths)
if err != nil {
    var pe *os.PathError
    if errors.As(err, &pe) {
        log.Warnf("skipping unstattable path %s: %v", pe.Path, err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Register, Run, or timeToComputeMTimes (directly or via the file watcher) on a path that exists but is not statable: permission denied on a directory component, an I/O error, a broken symlink on some filesystems, a path that is too long, or a dangling mount/NFS stale handle.

Common situations: Running Skaffold in a container without read permission on a watched directory; watching a directory on a network volume that dropped; a dependency path inside a directory with restrictive permissions after a chmod change; watching files under /proc or another pseudo-filesystem where stat can fail transiently.

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/6835dfdc9c484dbd. Report an issue: GitHub.