{"record":{"id":"bbe7be03b4fdc522","repo":"ipfs/kubo","slug":"writing-s-w","errorCode":null,"errorMessage":"writing %s: %w","messagePattern":"writing (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/commands/keystore.go","lineNumber":379,"sourceCode":"\toutPath, err = resolveSymlink(outPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfile, err := atomicfile.New(outPath, exportedKeyFileMode)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating temporary file for %s: %w\", outPath, err)\n\t}\n\tif err := writeKey(file); err != nil {\n\t\treturn errors.Join(err, file.Abort())\n\t}\n\t// Flush before the rename, so a crash cannot leave an empty file where the\n\t// previous export was.\n\tif err := file.Sync(); err != nil {\n\t\treturn errors.Join(fmt.Errorf(\"flushing %s: %w\", outPath, err), file.Abort())\n\t}\n\tif err := file.Close(); err != nil {\n\t\treturn fmt.Errorf(\"writing %s: %w\", outPath, err)\n\t}\n\treturn nil\n}\n\n// resolveSymlink returns the path a chain of symlinks ends at.\n// filepath.EvalSymlinks cannot be used on the path as a whole: it fails when\n// the last link points at a file that does not exist yet, and such a link\n// still says where the key belongs. A path that cannot be inspected is\n// returned unchanged, so that the caller's write reports the problem.\nfunc resolveSymlink(path string) (string, error) {\n\tfor range maxSymlinkHops {\n\t\tinfo, err := os.Lstat(path)\n\t\tif err != nil || info.Mode()&os.ModeSymlink == 0 {\n\t\t\treturn path, nil\n\t\t}\n\t\ttarget, err := os.Readlink(path)\n\t\tif err != nil {\n\t\t\treturn \"\", err","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/commands/keystore.go#L361-L397","documentation":"After a successful Sync, the temp file is closed and, inside atomicfile, renamed over the target. This error wraps a failure from file.Close(), which for atomicfile includes the rename operation. The export therefore did not complete: either the flush/close syscall failed or the rename could not replace the target (e.g. it cannot be renamed over).","triggerScenarios":"`ipfs key export -o <path>` where the target is a bind-mounted file, a mount point, or the parent directory disallows rename (sticky-bit/dir permission issues, cross-device conditions). Also close-time write-back errors on failing storage.","commonSituations":"Trying to overwrite a file that is a bind mount inside a container; exporting over a file in a directory with the sticky bit not owned by the user; overlayfs/docker volume edge cases where rename over the target fails.","solutions":["Check the wrapped errno: EBUSY/EXDEV/EPERM indicate the target cannot be renamed over — export to a different path","If the target is a bind mount, write to a new file and remount/copy instead","Verify you own the parent directory or have write+execute on it","Retry after removing anything special about the target path (mount point, immutable flag: chattr -i)"],"exampleFix":"// before\nipfs key export mykey -o /etc/config/identity.key   # bind-mounted\n// after\nipfs key export mykey -o /tmp/identity.key && cp /tmp/identity.key /etc/config/identity.key","handlingStrategy":"validation","validationCode":"# ensure target is not a mount point / bind mount and parent is writable\nmountpoint -q \"$out\" && echo 'cannot rename over mount point'\nfindmnt -T \"$out\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never target bind-mounted files or mount points directly with -o","Ensure you have write permission on the parent directory (rename needs it)","Avoid overlay/immutable-flagged targets; clear chattr +i if set"],"tags":["cli","keystore","filesystem","rename"],"backgroundTag":"atomic-rename-failed","analyzedSha":"329838acdfafae224582930457efe80aa217afc0","analyzedAt":"2026-09-03T18:30:52.135Z","contentChangedAt":"2026-09-03T18:30:52.135Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}