benbjohnson/litestream · warning

rename hydration meta: %w

Error message

rename hydration meta: %w

What it means

Hydrator.saveMeta wraps os.Rename failures as "rename hydration meta". The atomic temp-file-to-meta rename is the commit point for the saved TXID; failure leaves no updated meta, so the next open falls back to full hydration.

Source

Thrown at vfs.go:1021

		if closeErr := tmp.Close(); closeErr != nil {
			h.logger.Warn("failed to close temp meta file during cleanup", "error", closeErr)
		}
		if removeErr := os.Remove(tmpPath); removeErr != nil {
			h.logger.Warn("failed to remove temp meta file during cleanup", "error", removeErr)
		}
		return fmt.Errorf("sync temp meta file: %w", err)
	}
	if err := tmp.Close(); err != nil {
		if removeErr := os.Remove(tmpPath); removeErr != nil {
			h.logger.Warn("failed to remove temp meta file during cleanup", "error", removeErr)
		}
		return fmt.Errorf("close temp meta file: %w", err)
	}
	if err := os.Rename(tmpPath, h.metaPath()); err != nil {
		if removeErr := os.Remove(tmpPath); removeErr != nil {
			h.logger.Warn("failed to remove temp meta file during cleanup", "error", removeErr)
		}
		return fmt.Errorf("rename hydration meta: %w", err)
	}
	if err := syncDir(filepath.Dir(h.metaPath())); err != nil {
		return fmt.Errorf("sync hydration meta directory: %w", err)
	}
	return nil
}

func syncDir(path string) error {
	dir, err := os.Open(path)
	if err != nil {
		return err
	}
	defer dir.Close()
	return dir.Sync()
}

func NewVFSFile(client ReplicaClient, name string, logger *slog.Logger) *VFSFile {
	f := &VFSFile{

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Verify the hydration directory still exists and is writable (ls -ld)
  2. Check container/SELinux policies denying rename in the hydration directory
  3. Avoid network/overlay filesystems for hydration state; use local disk
  4. Non-fatal for replication: restart litestream after fixing the filesystem to re-hydrate
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the target path is renameable: same-dir, writable parent
dir := filepath.Dir(hydrationPath)
if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
	// recreate the directory before opening litestream
}

Try / catch

if err := saveMeta(); err != nil {
	var linkErr *os.LinkError
	if errors.As(err, &linkErr) {
		// inspect linkErr.Err (EACCES, ENOENT, EXDEV) and fix filesystem
	}
}

Prevention

When it happens

Trigger: Rename across a filesystem boundary is not the case here (same directory), but the target directory may have become read-only or been removed; EXDEV-style errors from overlay/network filesystems; target meta path locked by another process on filesystems with mandatory locking; ENOSPC on directory metadata update.

Common situations: OverlayFS/container volume quirks; the hydration directory deleted mid-run; SELinux/AppArmor denying the rename operation.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/4dc26c5deef3cf37. Report an issue: GitHub.