benbjohnson/litestream · error
sync txid file: %w
Error message
sync txid file: %w
What it means
WriteTXIDFile persists the replica's last-applied TXID to a sidecar '<db>-txid' file using a temp-file + fsync + rename protocol. This error wraps f.Sync(), meaning the OS failed to flush the temp file's data to stable storage. Litestream fsyncs before the atomic rename so the TXID survives a crash; a sync failure means durability cannot be guaranteed for the written TXID.
Source
Thrown at replica.go:1736
// WriteTXIDFile atomically writes a TXID to a sidecar file at <outputPath>-txid.
// Uses temp-file + fsync + rename for crash safety.
func WriteTXIDFile(outputPath string, txid ltx.TXID) error {
txidPath := TXIDPath(outputPath)
tmpPath := txidPath + ".tmp"
f, err := os.Create(tmpPath)
if err != nil {
return fmt.Errorf("create txid temp file: %w", err)
}
defer f.Close()
defer os.Remove(tmpPath)
if _, err := fmt.Fprintln(f, txid); err != nil {
return fmt.Errorf("write txid: %w", err)
}
if err := f.Sync(); err != nil {
return fmt.Errorf("sync txid file: %w", err)
}
if err := f.Close(); err != nil {
return fmt.Errorf("close txid file: %w", err)
}
if err := os.Rename(tmpPath, txidPath); err != nil {
return fmt.Errorf("rename txid file: %w", err)
}
if err := internal.FsyncDir(filepath.Dir(txidPath)); err != nil {
return fmt.Errorf("sync txid dir: %w", err)
}
return nil
}
// ReadTXIDFile reads the TXID from a sidecar file at <outputPath>-txid.
// Returns 0, nil if the file does not exist (first run).View on GitHub (pinned to 4ed7a308f6)
Solutions
- Free disk space on the volume containing the output path and retry the operation
- Check dmesg / system logs for underlying device I/O errors and repair or replace the failing disk
- Verify the output path is on a local filesystem that supports fsync, not an unreliable network mount
- Delete any stale '<outputPath>-txid.tmp' file and rerun; the code removes the temp file on error via defer
Example fix
// before: silently ignoring the write error
if err := WriteTXIDFile(db.Path(), txid); err != nil { log.Println(err) }
// after: fail loudly so the caller can resync
if err := WriteTXIDFile(db.Path(), txid); err != nil {
return fmt.Errorf("persist txid for %s: %w", db.Path(), err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: check writable space before writing
if st, err := os.Statfs(filepath.Dir(TXIDPath(outputPath))); err == nil && st.Bavail*uint64(st.Bsize) < 1<<20 {
return fmt.Errorf("insufficient disk space for txid file")
} Type guard
func canWriteDir(dir string) bool {
f, err := os.CreateTemp(dir, ".probe")
if err != nil { return false }
f.Close(); os.Remove(f.Name())
return true
} Try / catch
if err := WriteTXIDFile(outputPath, txid); err != nil {
if errors.Is(err, syscall.ENOSPC) {
// free space / alert, then retry
} else {
return fmt.Errorf("persist txid: %w", err)
}
} Prevention
- Monitor free disk space on the volume holding database and sidecar files
- Keep database output paths on local POSIX filesystems, not NFS
- Ensure the litestream user owns the output directory
- Clean stale '*.tmp' sidecar files after crashes
When it happens
Trigger: Calling WriteTXIDFile (directly or via replica restore/apply flows) when the filesystem rejects fsync: full disk on the volume holding the output path, I/O errors on the underlying device, or filesystems/containers where fsync is not supported on the temp file '<outputPath>-txid.tmp'.
Common situations: Disk-full on the host or in a Docker container after a large restore; NFS or network filesystems with unreliable fsync; failing disk reported through writeback errors; running in environments (some overlayfs setups) where fsync on a freshly created file errors.
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/89e6db1cd8205c01.
Report an issue: GitHub.