dagger/dagger · error
failed to stat synctarget dest %s: %w
Error message
failed to stat synctarget dest %s: %w
What it means
In file/tar-stream mode, DiffCopy stats the destination path to decide how to write the file. If os.Stat fails for any reason other than 'does not exist', the situation is unrecoverable and the handler wraps the stat error with this message.
Source
Thrown at engine/client/filesync.go:292
// an error when path is a pre-existing directory.
allowParentDirPath := opts.AllowParentDirPath
// File exports specifically (as opposed to container tar exports) have an original filename that we will
// use in the case where dest is a directory and allowParentDirPath is set, in which case we need to know
// what to name the file underneath the pre-existing directory.
fileOriginalName := opts.FileOriginalName
var destParentDir string
var finalDestPath string
stat, err := os.Stat(absPath)
switch {
case errors.Is(err, os.ErrNotExist):
// we are writing the file to a new path
destParentDir = filepath.Dir(absPath)
finalDestPath = absPath
case err != nil:
// something went unrecoverably wrong if stat failed and it wasn't just because the path didn't exist
return fmt.Errorf("failed to stat synctarget dest %s: %w", absPath, err)
case !stat.IsDir():
// we are overwriting an existing file
destParentDir = filepath.Dir(absPath)
finalDestPath = absPath
case !allowParentDirPath:
// we are writing to an existing directory, but allowParentDirPath is not set, so fail
return fmt.Errorf("destination %q is a directory; must be a file path unless allowParentDirPath is set", absPath)
default:
// we are writing to an existing directory, and allowParentDirPath is set,
// so write the file under the directory using the same file name as the source file
if fileOriginalName == "" {
// NOTE: we could instead just default to some name like container.tar or something if desired
return fmt.Errorf("cannot export container tar to existing directory %q", absPath)
}
destParentDir = absPath
finalDestPath = filepath.Join(destParentDir, fileOriginalName)
}
View on GitHub (pinned to 82ba2681db)
Solutions
- Fix permissions so the sync user can traverse every parent directory of the destination
- Remove symlink loops or shorten the destination path
- Verify the parent path exists and the mount is healthy
- Export to a simpler, local, user-writable path to isolate the issue
Example fix
// before
await file.export("/mnt/nfs/very/deep/path/out.tar") // flaky NFS
// after
await file.export(filepath.Join(os.TempDir(), "out.tar"))
// then move into place yourself Defensive patterns
Strategy: validation
Validate before calling
// walk every parent to catch EACCES/ELOOP before exporting
p := filepath.Dir(dest)
for {
if _, err := os.Stat(p); err != nil {
return fmt.Errorf("cannot stat %s: %w", p, err)
}
parent := filepath.Dir(p)
if parent == p { break }
p = parent
} Type guard
func statable(path string) bool { _, err := os.Stat(path); return err == nil } Prevention
- Keep export destinations shallow and local
- Avoid symlinks in destination paths
- Use paths well under OS length limits (esp. Windows)
- Verify mounts are healthy before long-running export jobs
When it happens
Trigger: os.Stat on the export destination fails with e.g. EACCES on a parent directory (cannot even check existence), ELOOP from a symlink cycle, ENAMETOOLONG, or I/O errors on the device.
Common situations: Destination nested under a directory the sync user cannot traverse; broken symlink loops after repeated exports; overly long paths from deep artifact trees (Windows MAX_PATH); failing network mounts.
Related errors
- stat path: %w
- %s: no such file or directory
- stat removed path %s: %w
- stat modified path %s: %w
- stat %s: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/dc79f5fd9067f315.
Report an issue: GitHub.