GoogleContainerTools/skaffold · error

filepath walk: %w

Error message

filepath walk: %w

What it means

After globbing, ExpandPathsGlob walks each matched path with walk.From(f).WhenIsFile().Do(...) to collect real files; this error wraps a failure from that walk. The walk fails when traversing a matched path hits an unreadable directory, a broken symlink being resolved, or the file disappears between globbing and walking. It aggregates the underlying walk error from dependency/test-path expansion.

Source

Thrown at pkg/skaffold/util/util.go:106

			// This is a file reference, so just add it
			set.Add(path)
			continue
		}

		files, err := filepath.Glob(path)
		if err != nil {
			return nil, fmt.Errorf("glob: %w", err)
		}
		if len(files) == 0 {
			log.Entry(context.TODO()).Warnf("%s did not match any file", p)
		}

		for _, f := range files {
			if err := walk.From(f).WhenIsFile().Do(func(path string, _ walk.Dirent) error {
				set.Add(path)
				return nil
			}); err != nil {
				return nil, fmt.Errorf("filepath walk: %w", err)
			}
		}
	}

	return set.Files(), nil
}

func Ptr[T any](t T) *T {
	o := t
	return &o
}

func IsURL(s string) bool {
	return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://")
}

// VerifyOrCreateFile checks if a file exists at the given path,
// and if not, creates all parent directories and creates the file.

View on GitHub (pinned to a1189de023)

Solutions

  1. Check and fix read/execute permissions on every directory matched by the glob pattern.
  2. Remove or repair broken symlinks among the matched paths (find . -xtype l).
  3. Re-run — if a concurrent process deletes files mid-walk, make the dependency set stable before running Skaffold.
  4. Narrow the glob pattern so it only matches files that actually exist and are accessible.

Example fix

// before
structureTests: ["tests/**/*"]   # matches broken symlink tests/latest -> /nonexistent
// after
ln -sf /opt/tests/latest.json tests/latest.json   # repair the symlink
tests/latest.json
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check every glob match is a readable file
for _, f := range files {
    info, err := os.Stat(f)
    if err != nil || info.IsDir() {
        return fmt.Errorf("dependency %q not a readable file", f)
    }
    if fi, _ := os.Lstat(f); fi.Mode()&os.ModeSymlink != 0 {
        if _, err := os.Stat(f); err != nil {
            return fmt.Errorf("broken symlink %q", f)
        }
    }
}

Try / catch

deps, err := util.ExpandPathsGlob(fs, paths)
if err != nil {
    if strings.Contains(err.Error(), "filepath walk:") {
        log.Entry(ctx).Warnf("walk failed (%v); cleaning symlinks and retrying", err)
        exec.Command("find", ".", "-xtype", "l", "-delete").Run()
        deps, err = util.ExpandPathsGlob(fs, paths)
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: A glob match points to a directory the process cannot read (permission denied), a file matched by the glob is deleted between the Glob call and the walk, or a symlink target loop/missing target is encountered while expanding test or manifest dependencies.

Common situations: CI checkouts where files are pruned concurrently; NFS/overlay volumes with stale directory handles; restricted read permissions on dependency directories after a chown change; broken symlinks committed into the repo (e.g. symlink to a mounted toolchain path).

Related errors


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