{"record":{"id":"c70b1cac4ba02002","repo":"dagger/dagger","slug":"failed-to-change-mode-w","errorCode":null,"errorMessage":"failed to change mode: %w","messagePattern":"failed to change mode: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/filesync/localfs.go","lineNumber":1066,"sourceCode":"\tif err := verifyExpectedChange(path, appliedChange.result(), expectedChangeKind, upperStat); err != nil {\n\t\tappliedChange.release()\n\t\treturn nil, 0, err\n\t}\n\treturn appliedChange, writtenBytes, nil\n}\n\nfunc (local *localFS) Walk(ctx context.Context, path string, walkFn fs.WalkDirFunc) error {\n\treturn local.filterFS.Walk(ctx, path, walkFn)\n}\n\nfunc rewriteMetadata(p string, upperStat *types.Stat) error {\n\tif err := os.Lchown(p, int(upperStat.Uid), int(upperStat.Gid)); err != nil {\n\t\treturn fmt.Errorf(\"failed to change owner: %w\", err)\n\t}\n\n\tif os.FileMode(upperStat.Mode)&os.ModeSymlink == 0 {\n\t\tif err := os.Chmod(p, os.FileMode(upperStat.Mode)); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to change mode: %w\", err)\n\t\t}\n\t}\n\n\tvar utimes [2]unix.Timespec\n\tutimes[0] = unix.NsecToTimespec(upperStat.ModTime)\n\tutimes[1] = utimes[0]\n\n\tif err := unix.UtimesNanoAt(unix.AT_FDCWD, p, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil {\n\t\treturn fmt.Errorf(\"failed to call utimes: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Check that the change applied by mutating methods is actually the one we thought we were applying. If not, the client\n// filesystem changed during the sync and we need to error out to avoid inconsistencies.\nfunc verifyExpectedChange(path string, appliedChange *ChangeWithStat, expectedKind ChangeKind, expectedStat *types.Stat) error {\n\tif appliedChange.kind == ChangeKindDelete || expectedKind == ChangeKindDelete {","sourceCodeStart":1048,"sourceCodeEnd":1084,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/engine/filesync/localfs.go#L1048-L1084","documentation":"Returned by rewriteMetadata in engine/filesync/localfs.go when os.Chmod(p, mode) fails while restoring a synced file's permission bits (skipped for symlinks), and re-wrapped by WriteFile as 'failed to rewrite file metadata'. The file data is already written; the library aborts because the copy's permissions would otherwise diverge from the source.","triggerScenarios":"os.Chmod on the freshly written file fails — typically EPERM because the process doesn't own the file (e.g. a preceding Lchown changed ownership to another user in a non-root context) or an immutable/read-only attribute is set; also possible on filesystems that don't support permission bits.","commonSituations":"Non-root flow where Lchown succeeded to a different owner making the process no longer the file owner (EPERM on chmod); files with chattr +i / immutable flag on the destination; FAT/exFAT or restricted NFS mounts; read-only bind mounts.","solutions":["Run as root or ensure the process retains ownership of the file so chmod is permitted (check ordering of chown/chmod when unprivileged)","Clear immutable flags on the destination: chattr -i <file> (or remove the read-only mount option)","Confirm the destination filesystem supports POSIX permissions; avoid FAT/exFAT targets or remount with proper support","Check the wrapped errno in the error chain to distinguish EPERM (permissions) from EROFS (read-only fs) and fix accordingly"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// ensure the process owns the file it is about to chmod and fs is not read-only\ninfo, err := os.Lstat(p)\nif err != nil { return err }\nif os.Geteuid() != 0 && info.Sys().(*syscall.Stat_t).Uid != uint32(os.Geteuid()) {\n\treturn fmt.Errorf(\"process does not own %s; chmod will EPERM\", p)\n}\nif err := unix.Access(dir, unix.W_OK); err != nil {\n\treturn fmt.Errorf(\"destination not writable (read-only fs?): %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := rewriteMetadata(p, upperStat)\nvar pathErr *os.PathError\nif errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.EPERM) {\n\t// un-chown first / run as root, or chattr -i the target, then retry\n} else if errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.EROFS) {\n\t// remount destination read-write\n}","preventionTips":["When unprivileged, avoid chowning files to other users before chmod (chown-then-chmod ordering breaks EPERM-free flow)","Clear immutable attributes (chattr -i) on destination files before re-syncing","Use destination filesystems that support permission bits (not FAT/exFAT)","Ensure the destination mount is not read-only for the engine's user"],"tags":["permissions","filesystem","chmod"],"backgroundTag":"chmod-permission-denied","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}