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
- Verify the hydration directory still exists and is writable (ls -ld)
- Check container/SELinux policies denying rename in the hydration directory
- Avoid network/overlay filesystems for hydration state; use local disk
- 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
- Keep hydration state on simple local filesystems, not overlay/network mounts
- Audit SELinux/AppArmor policies for write+rename in the data directory
- Ensure the hydration directory is not removed by cleanup jobs at runtime
- Know the blast radius: only resume efficiency is lost; the replica remains the source of truth
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
- rename L0 file: %w
- rename ltx file: %w
- rename to output path: %w
- rename txid file: %w
- create hydration directory: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/4dc26c5deef3cf37.
Report an issue: GitHub.