benbjohnson/litestream · error
sync ltx dir: %w
Error message
sync ltx dir: %w
What it means
After renaming the LTX file, litestream fsyncs the parent directory so the rename is durable across crashes. A failure here is wrapped as 'sync ltx dir:'; like the rename failure, it clears cached file-info and position state because durability of the new LTX file is not guaranteed.
Source
Thrown at db.go:2244
// Atomically rename file to final path.
db.setSyncDiagPhase(diagPhaseRenameLTX, func(s *diagState) {
s.txID = txID
s.walSize = sz
})
if err := os.Rename(tmpFilename, filename); err != nil {
db.maxLTXFileInfos.Lock()
delete(db.maxLTXFileInfos.m, 0) // clear cache if in unknown state
db.maxLTXFileInfos.Unlock()
db.invalidatePosCache()
return result, fmt.Errorf("rename ltx file: %w", err)
}
if err := internal.FsyncDir(filepath.Dir(filename)); err != nil {
db.maxLTXFileInfos.Lock()
delete(db.maxLTXFileInfos.m, 0) // clear cache if in unknown state
db.maxLTXFileInfos.Unlock()
db.invalidatePosCache()
return result, fmt.Errorf("sync ltx dir: %w", err)
}
result.synced = true
result.l0FileInfo = <x.FileInfo{
Level: 0,
MinTXID: txID,
MaxTXID: txID,
CreatedAt: time.Now(),
Size: enc.N(),
}
encPos := enc.PostApplyPos()
result.pos = &encPos
// Track the logical end of WAL content for checkpoint decisions.
// This is the WALOffset + WALSize from the LTX we just created.
// Using this instead of file size prevents issue #997 where stale
// frames with old salt values cause perpetual checkpoint triggering.View on GitHub (pinned to 4ed7a308f6)
Solutions
- Confirm the LTX directory exists and is openable by the process at failure time.
- If the filesystem does not support directory fsync, relocate the data directory to a POSIX-compliant local filesystem.
- Retry the sync; if the rename actually persisted, the next successful sync repairs cached state.
- Investigate cleanup jobs that might delete the LTX directory during active syncs.
Example fix
// before path: /mnt/efs/db # NFS: dir fsync unsupported/erratic // after path: /var/lib/litestream/db # local ext4/xfs
Defensive patterns
Strategy: try-catch
Type guard
func supportsDirFsync(dir string) error {
return internal.FsyncDir(dir) // pre-flight in setup
} Try / catch
if err := db.Sync(ctx); err != nil {
if strings.Contains(err.Error(), "sync ltx dir") {
// verify dir fsync support; consider relocating storage
}
return err
} Prevention
- Run litestream on ext4/xfs or another directory-fsync-capable FS.
- Test FsyncDir on your mount during deployment.
- Prevent cleanup jobs from deleting the LTX directory mid-sync.
- Verify directory permissions for the litestream user.
When it happens
Trigger: internal.FsyncDir(filepath.Dir(filename)) at db.go:2239 returned an error: the directory fd could not be opened (permissions, deleted dir), or fsync on directories is unsupported by the filesystem (some NFS/FUSE mounts, certain Windows configurations).
Common situations: Data directory on a network or FUSE filesystem that rejects directory fsync; the LTX directory removed concurrently by retention cleanup; permission changes preventing opening the directory.
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/be0ae35ec04abc73.
Report an issue: GitHub.