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
- Fix the underlying os.Stat error shown in the wrapped cause (permissions, stale mount, I/O).
- Check that the watched path exists and all parent directories grant read+execute to the user running Skaffold.
- Remove or correct the offending dependency/glob in skaffold.yaml if it points at a pseudo-filesystem or unstable path.
- 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
- Pre-flight os.Stat every watched path at startup and log/remove failures.
- Ensure watched directories grant read+execute to the Skaffold process user.
- Avoid watching pseudo-filesystems (/proc, /sys) and NFS mounts in dependencies.
- Handle os.ErrNotExist separately — it is intentionally tolerated by the monitor.
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
- writing %q to %q: %w
- reading .dockerignore: %w
- walking workspace: %w
- stating file %q: %w
- failed to create directory: %v
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/6835dfdc9c484dbd.
Report an issue: GitHub.