ipfs/kubo · error

flushing %s: %w

Error message

flushing %s: %w

What it means

After writing the exported key into the temp file, writeExportedKey calls file.Sync() to flush it to stable storage before the atomic rename, so a crash can never leave an empty or truncated key file. This error joins the fsync failure with the temp file's Abort. It indicates an I/O-layer problem persisting the data, not a key-format problem.

Source

Thrown at core/commands/keystore.go:376

	// The key is written next to the target and renamed over it, so replace
	// what a symlink points at rather than the symlink itself.
	outPath, err = resolveSymlink(outPath)
	if err != nil {
		return err
	}

	file, err := atomicfile.New(outPath, exportedKeyFileMode)
	if err != nil {
		return fmt.Errorf("creating temporary file for %s: %w", outPath, err)
	}
	if err := writeKey(file); err != nil {
		return errors.Join(err, file.Abort())
	}
	// Flush before the rename, so a crash cannot leave an empty file where the
	// previous export was.
	if err := file.Sync(); err != nil {
		return errors.Join(fmt.Errorf("flushing %s: %w", outPath, err), file.Abort())
	}
	if err := file.Close(); err != nil {
		return fmt.Errorf("writing %s: %w", outPath, err)
	}
	return nil
}

// resolveSymlink returns the path a chain of symlinks ends at.
// filepath.EvalSymlinks cannot be used on the path as a whole: it fails when
// the last link points at a file that does not exist yet, and such a link
// still says where the key belongs. A path that cannot be inspected is
// returned unchanged, so that the caller's write reports the problem.
func resolveSymlink(path string) (string, error) {
	for range maxSymlinkHops {
		info, err := os.Lstat(path)
		if err != nil || info.Mode()&os.ModeSymlink == 0 {
			return path, nil
		}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Check the wrapped errno: EIO usually means failing hardware — run fsck or replace the disk
  2. Retry the export to a different filesystem (e.g. local disk instead of a network mount)
  3. The temp file was aborted, so no partial file remains — re-run once hardware/fs is healthy
  4. Avoid exporting directly onto fuse/network filesystems known to reject fsync

Example fix

// before
ipfs key export mykey -o /mnt/flaky-nfs/mykey.pem
// after
ipfs key export mykey -o /root/mykey.pem && cp /root/mykey.pem /mnt/flaky-nfs/
Defensive patterns

Strategy: retry

Validate before calling

// Prefer local, fsync-capable filesystems for key export
mount | grep "$(df --output=target "$(dirname "$out")" | tail -1)"  # avoid nfs/fuse targets

Try / catch

if err := writeExportedKey(outPath, r, fmt); err != nil && strings.Contains(err.Error(), "flushing") {
    // transient fsync failure: retry once on a local filesystem
    return retryExport(outPath, r, fmt)
}

Prevention

When it happens

Trigger: `ipfs key export` to a filesystem whose fsync fails: disk errors, some network filesystems (NFS oddities), full journal, or exporting onto virtual filesystems that do not support fsync (certain fuse mounts, /proc-like fs).

Common situations: Exporting to a flaky USB drive or failing disk; fuse/network mounts with unreliable fsync; container storage drivers with fsync quirks.

Related errors


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/f8b28b4fa7804db3. Report an issue: GitHub.