dagger/dagger · error
failed to rewrite file metadata: %w
Error message
failed to rewrite file metadata: %w
What it means
Wrapped by localFS.WriteFile when rewriteMetadata(fullPath, upperStat) fails after the file was successfully written and closed. rewriteMetadata restores the upstream file's ownership (Lchown), permission mode (Chmod), and timestamps (utimes). The file content is correct, but its metadata could not be applied, so the sync is aborted to avoid leaving an inconsistent copy.
Source
Thrown at engine/filesync/localfs.go:1027
return nil, err
}
defer f.Close()
h := newHashFromStat(upperStat)
copyBuf := copyBufferPool.Get().(*[]byte)
written, err := io.CopyBuffer(io.MultiWriter(f, h), reader, *copyBuf)
writtenBytes = written
copyBufferPool.Put(copyBuf)
if err != nil {
return nil, fmt.Errorf("failed to copy contents: %w", err)
}
if err := f.Close(); err != nil {
return nil, fmt.Errorf("failed to close file: %w", err)
}
if err := rewriteMetadata(fullPath, upperStat); err != nil {
return nil, fmt.Errorf("failed to rewrite file metadata: %w", err)
}
// store the hash in an xattr so GetPreviousChange above can use that instead of re-hashing the file
dgst := digest.NewDigest(hashutil.XXH3, h)
if err := sysx.Setxattr(fullPath, hashXattrKey, []byte(dgst.String()), 0); err != nil {
return nil, fmt.Errorf("failed to set content hash xattr: %w", err)
}
return &ChangeWithStat{
kind: expectedChangeKind,
stat: &HashedStatInfo{
StatInfo: StatInfo{upperStat},
dgst: dgst,
},
}, nil
})
if err != nil {
return nil, 0, errView on GitHub (pinned to 82ba2681db)
Solutions
- Run the operation with sufficient privileges (root or a user that owns the target uid/gid), or in a rootless setup ensure user namespace mapping permits the chown
- Check that the destination filesystem supports ownership/permission/timestamp changes (avoid FAT/exFAT destinations, check mount options like nosuid/user mapping)
- Inspect the wrapped errno in the error message (%w chain) to identify which of chown/chmod/utimes failed and address that specific syscall restriction
- If security modules (SELinux/AppArmor) deny the operation, adjust the policy or run outside the restricted context
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: can we chown/chmod/utimes on this target?
probe := filepath.Join(destDir, ".meta-probe")
os.WriteFile(probe, []byte("x"), 0o600)
defer os.Remove(probe)
if err := os.Chown(probe, os.Getuid(), os.Getgid()); err != nil {
return fmt.Errorf("target fs rejects chown: %w", err)
}
if err := os.Chtimes(probe, time.Now(), time.Now()); err != nil {
return fmt.Errorf("target fs rejects utimes: %w", err)
} Try / catch
err := rewriteMetadata(fullPath, upperStat)
if err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.EPERM) {
// run privileged or adjust userns mapping, then retry
}
return fmt.Errorf("metadata restore failed: %w", err)
} Prevention
- Run dagger with privileges adequate for the ownership of the files being synced, or use rootless mode with correct subuid/subgid mappings
- Choose destination filesystems that support full POSIX metadata (ext4/xfs/btrfs/apfs), not FAT/exFAT
- Keep source file ownership within the user/namespace range available to the engine
- Test the sync target with a probe file that exercises chown/chmod/utimes before large operations
When it happens
Trigger: rewriteMetadata returns an error during WriteFile — most commonly Lchown failing because the process lacks privileges to set the target uid/gid, Chmod failing on the target filesystem, or utimes failing on a filesystem that doesn't support setting timestamps.
Common situations: Running the dagger engine/CLI as a non-root user while syncing files owned by other uids/gids (common in containerized or rootless setups); syncing onto a filesystem that ignores or rejects chown (some NFS mounts, FAT/exFAT, bind mounts with userns remapping); SELinux/AppArmor restrictions denying chown or chmod.
Related errors
- remove path %s: %w
- failed to create synctarget dest dir %s: %w
- failed to create synctarget dest file %s: %w
- failed to read go.mod at %s: %w
- failed to set chown %s: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/686d93ab084647c7.
Report an issue: GitHub.