benbjohnson/litestream · error
close L0 file: %w
Error message
close L0 file: %w
What it means
After fsync, Litestream closes the temp file with tmpFile.Close(). This error wraps a failure of that close, indicating pending buffered data could not be flushed by the OS or the file descriptor is in a bad state. The partially staged file is discarded and the LTX file is not adopted.
Source
Thrown at db.go:1652
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
}
// verify ensures the current LTX state matches where it left off from
// the real WAL. Check info.ok if verification was successful.
func (db *DB) verify(ctx context.Context, state *syncState) (info syncInfo, err error) {View on GitHub (pinned to 4ed7a308f6)
Solutions
- Check dmesg/journal for block-device I/O errors on the data volume.
- Raise the process file-descriptor limit (ulimit -n / LimitNOFILE in systemd) if fd exhaustion is reported.
- Fix or replace failing storage; close errors on local disks almost always indicate hardware/driver problems.
- Retry after remediation — the temp file is cleaned up and the next sync refetches.
Example fix
# before: systemd service hits fd limit # after: raise LimitNOFILE for litestream [Service] LimitNOFILE=65536
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure adequate fd headroom
var lim syscall.Rlimit
syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim)
if lim.Cur < 4096 { log.Printf("low RLIMIT_NOFILE: %d", lim.Cur) } Type guard
null
Try / catch
if err := tmpFile.Close(); err != nil {
return fmt.Errorf("close L0 file: %w", err)
} // close errors are almost always EIO: check hardware/driver logs, then retry Prevention
- Set LimitNOFILE=65536 for the litestream systemd unit
- Monitor storage hardware health
- Check journal/dmesg when close errors appear
- Avoid NFS for the LTX directory where writeback is unreliable
When it happens
Trigger: checkDatabaseBehindReplica calls tmpFile.Close() after a successful Sync and close fails — rare, usually EIO on flush of remaining buffers, or fd exhaustion earlier in the process causing odd fd states.
Common situations: Underlying storage device errors (dmesg shows I/O errors); file descriptor limit (ulimit -n) exhausted after many open LTX files; NFS server issues delaying writeback.
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
- failed to scan directory %s: %w
- remove L0 directory: %w
- recreate L0 directory: %w
- create temp L0 file: %w
- rename L0 file: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/bc873fe7de25e00b.
Report an issue: GitHub.