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, err

View on GitHub (pinned to 82ba2681db)

Solutions

  1. 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
  2. Check that the destination filesystem supports ownership/permission/timestamp changes (avoid FAT/exFAT destinations, check mount options like nosuid/user mapping)
  3. Inspect the wrapped errno in the error message (%w chain) to identify which of chown/chmod/utimes failed and address that specific syscall restriction
  4. 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

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


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/686d93ab084647c7. Report an issue: GitHub.