benbjohnson/litestream · error

sync L0 file: %w

Error message

sync L0 file: %w

What it means

After copying, the temp file is flushed to disk with tmpFile.Sync() before rename. This error wraps a failure of fsync on the temp L0 file, meaning the fetched LTX data could not be durably committed to storage and the file is abandoned.

Source

Thrown at db.go:1648

	// Write to temp file and atomically rename
	localPath := db.LTXPath(0, minTXID, maxTXID)
	tmpPath := localPath + ".tmp"

	tmpFile, err := os.Create(tmpPath)
	if err != nil {
		return fmt.Errorf("create temp L0 file: %w", err)
	}
	defer func() { _ = os.Remove(tmpPath) }() // Clean up temp file on error

	if _, err := io.Copy(tmpFile, reader); err != nil {
		_ = tmpFile.Close()
		return fmt.Errorf("copy L0 file: %w", err)
	}

	if err := tmpFile.Sync(); err != nil {
		_ = tmpFile.Close()
		return fmt.Errorf("sync L0 file: %w", err)
	}

	if err := tmpFile.Close(); err != nil {
		return fmt.Errorf("close L0 file: %w", err)
	}

	// Atomically rename temp file to final path
	if err := os.Rename(tmpPath, localPath); err != nil {
		return fmt.Errorf("rename L0 file: %w", err)
	}
	db.invalidatePosCache()

	db.Logger.Info("fetched latest L0 file from replica",
		"min_txid", minTXID,
		"max_txid", maxTXID)

	return nil
}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Free disk space (df -h) — ENOSPC at fsync time is common even when create/copy succeeded.
  2. Check dmesg/smart data for device I/O errors on the data volume.
  3. If running in a container, verify the storage driver supports reliable fsync (avoid tmpfs for the LTX dir).
  4. Retry after fixing the disk; the .tmp file is cleaned up automatically on error.

Example fix

// before: data volume at 100%
$ df -h /var/lib/db  # 100% used
// after: free space or grow volume before restarting litestream
$ systemctl stop litestream && rm -f /var/lib/db/*.tmp && systemctl start litestream
Defensive patterns

Strategy: try-catch

Validate before calling

// Keep headroom: fail early if disk is nearly full
st, _ := os.Statfs(dataDir)
if st.Bavail*uint64(st.Bsize) < 128*1024*1024 {
    log.Printf("refusing fetch, low disk")
}

Type guard

null

Try / catch

if err := tmpFile.Sync(); err != nil {
    _ = tmpFile.Close()
    return fmt.Errorf("sync L0 file: %w", err)
} // ENOSPC -> free space; EIO -> check dmesg for device errors

Prevention

When it happens

Trigger: checkDatabaseBehindReplica calls tmpFile.Sync() after a successful io.Copy and the OS returns an error — typically ENOSPC (no space left to flush dirty pages) or EIO (underlying device failure).

Common situations: Disk filling up between the copy and the sync; failing or failing-over storage hardware; container filesystems (some overlay/tmpfs setups) returning errors on fsync.

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/1fd0fa50fce6e3d9. Report an issue: GitHub.