GoogleContainerTools/skaffold · error

walking workspace: %w

Error message

walking workspace: %w

What it means

SyncMap fails with "walking workspace" when walkWorkspaceWithDestinations errors while traversing the artifact workspace to match files against COPY/ADD destinations from the Dockerfile. The walk resolves syncable sources to container destinations, so unreadable directories or bad symlinks abort the whole sync-map computation.

Source

Thrown at pkg/skaffold/docker/syncmap.go:52

	absDockerfilePath, err := NormalizeDockerfilePath(workspace, dockerfilePath)
	if err != nil {
		return nil, fmt.Errorf("normalizing dockerfile path: %w", err)
	}

	// only the COPY/ADD commands from the last image are syncable
	fts, err := ReadCopyCmdsFromDockerfile(ctx, true, absDockerfilePath, workspace, buildArgs, cfg)
	if err != nil {
		return nil, err
	}

	excludes, err := readDockerignore(workspace, absDockerfilePath)
	if err != nil {
		return nil, fmt.Errorf("reading .dockerignore: %w", err)
	}

	srcByDest, err := walkWorkspaceWithDestinations(workspace, excludes, fts)
	if err != nil {
		return nil, fmt.Errorf("walking workspace: %w", err)
	}

	return invertMap(srcByDest), nil
}

// walkWorkspaceWithDestinations walks the given host directories and determines their
// location in the container. It returns a map of host path by container destination.
// Note: if you change this function, you might also want to modify `WalkWorkspace`.
func walkWorkspaceWithDestinations(workspace string, excludes []string, fts []FromTo) (map[string]string, error) {
	dockerIgnored, err := NewDockerIgnorePredicate(workspace, excludes)
	if err != nil {
		return nil, err
	}

	// Walk the workspace
	srcByDest := make(map[string]string)
	for _, ft := range fts {
		absFrom := filepath.Join(workspace, ft.From)

View on GitHub (pinned to a1189de023)

Solutions

  1. Run `find <workspace> ! -readable` to locate unreadable entries and fix their permissions or exclude them via .dockerignore.
  2. Remove or fix cyclic/broken symlinks in the workspace (`find <workspace> -type l -xtype l` for dangling links).
  3. Add problematic generated directories (node_modules, .git, build output) to .dockerignore so the walk skips them.
  4. Ensure no volumes/network mounts in the workspace disappeared during the walk.
  5. Check the wrapped error message — it names the specific path that failed.

Example fix

// before
# workspace contains root-owned build/ unreadable by CI user → walk fails
// after
printf 'build\nnode_modules\n.git\n' > .dockerignore
sudo chmod -R u+rwX,go+rX <workspace>
Defensive patterns

Strategy: validation

Validate before calling

func workspaceWalkable(workspace string) error {
	return filepath.Walk(workspace, func(path string, info os.FileInfo, err error) error {
		if err != nil { return fmt.Errorf("cannot walk %s: %w", path, err) }
		return nil
	})
}

Type guard

func isWalkable(workspace string) bool { return workspaceWalkable(workspace) == nil }

Try / catch

if err := workspaceWalkable(workspace); err != nil { return err }
if _, err := docker.SyncMap(ctx, workspace, dockerfilePath, buildArgs, cfg); err != nil {
	if strings.Contains(err.Error(), "walking workspace") {
		return fmt.Errorf("fix unreadable paths/symlinks in workspace (see wrapped error): %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: The workspace contains an unreadable subdirectory, a symlink loop, or a file that cannot be stat'd during the filepath walk; a COPY destination computed by the parser is invalid so the mapping step fails.

Common situations: Files created by root inside the workspace while Skaffold runs as a non-root user; node_modules or vendored dirs with circular symlinks; mounted volumes that drop offline mid-walk; COPY --from references producing odd destinations.

Related errors


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