GoogleContainerTools/skaffold · error
finding changed file %s relative to context %q: %w
Error message
finding changed file %s relative to context %q: %w
What it means
Skaffold's inferred file sync (inferredSyncItem) computes each changed/added file's path relative to the artifact's workspace so it can match it against the `sync.infer` patterns. When filepath.Rel(workspace, file) fails, the file cannot be expressed relative to the build context, and Skaffold wraps and returns the underlying error with this message.
Source
Thrown at pkg/skaffold/sync/sync.go:139
Delete: toDelete,
}, nil
}
// deleted files are no longer contained in the syncMap, so we need to rebuild
if len(e.Deleted) > 0 {
return nil, nil
}
syncMap, err := SyncMap(ctx, a, cfg)
if err != nil {
return nil, fmt.Errorf("inferring syncmap for image %q: %w", a.ImageName, err)
}
toCopy := make(map[string][]string)
for _, f := range append(e.Modified, e.Added...) {
relPath, err := filepath.Rel(a.Workspace, f)
if err != nil {
return nil, fmt.Errorf("finding changed file %s relative to context %q: %w", f, a.Workspace, err)
}
matches := false
for _, p := range a.Sync.Infer {
matches, err = doublestar.PathMatch(filepath.FromSlash(p), relPath)
if err != nil {
return nil, fmt.Errorf("pattern error for %q: %w", relPath, err)
}
if matches {
break
}
}
if !matches {
log.Entry(ctx).Infof("Changed file %s does not match any sync pattern. Skipping sync", relPath)
return nil, nil
}
if dsts, ok := syncMap[relPath]; ok {View on GitHub (pinned to a1189de023)
Solutions
- Verify the artifact's `workspace:` in skaffold.yaml is the absolute real path (resolve symlinks) containing the watched files
- Ensure the file watcher is started with the same absolute path passed as the artifact workspace
- Fix path casing/slash normalization (use filepath.FromSlash/Clean consistently) before calling NewItem
Example fix
// before workspace: ./service # relative, may resolve differently from watcher // after workspace: /home/dev/project/service # absolute, symlink-resolved
Defensive patterns
Strategy: validation
Validate before calling
ws, err := filepath.EvalSymlinks(a.Workspace)
if err != nil { return err }
for _, f := range append(e.Modified, e.Added...) {
if _, err := filepath.Rel(ws, f); err != nil {
return fmt.Errorf("file %s not under workspace %s", f, ws)
}
} Type guard
func fileInWorkspace(ws, f string) bool {
rel, err := filepath.Rel(ws, f)
return err == nil && rel != ".." && !strings.HasPrefix(rel, ".."+string(filepath.Separator))
} Try / catch
item, err := sync.NewItem(ctx, a, tag, e, cfg, builds)
if err != nil {
if strings.Contains(err.Error(), "relative to context") {
log.Warnf("skipping sync for out-of-workspace file: %v", err)
return nil
}
return err
} Prevention
- Use absolute, symlink-resolved workspace paths in skaffold.yaml
- Ensure the file watcher watches the same absolute path as the artifact workspace
- Normalize paths with filepath.Clean/EvalSymlinks before sync
When it happens
Trigger: A file event arrives whose absolute path is not underneath a.Workspace (e.g. event paths with different volume spellings, symlinked workspaces, or a workspace configured as a relative/nonexistent path), making filepath.Rel return an error.
Common situations: Watching files via a symlinked directory while skaffold.yaml names the real path; running on a case-insensitive filesystem where casing differs between config and events; Docker/K8s file-watch events referencing temp files outside the workspace.
Related errors
- changed file %s can't be found relative to context %q: %w
- failed to execute host %s hook %d for artifact %q: %w
- failed to execute container %s hook %d for artifact %q: %w
- watching files for artifact %q: %w
- watching test files: %w
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/edd3f403f1ad6cfe.
Report an issue: GitHub.