benbjohnson/litestream · error

write ltx from db: %w

Error message

write ltx from db: %w

What it means

db.writeLTXFromDB failed with a non-disk-full error while copying pages from the database file and WAL into the snapshot LTX. This is the page-copy phase of snapshot replication; failures here abort the snapshot and the staged temp file is removed by the deferred os.Remove.

Source

Thrown at db.go:2179

		}
		return result, fmt.Errorf("encode ltx header: %w", err)
	}

	// If we need a full snapshot, then copy from the database & WAL.
	// Otherwise, just copy incrementally from the WAL.
	if info.snapshotting {
		db.setSyncDiagPhase(diagPhaseWriteLTXFromDB,
			func(s *diagState) {
				s.txID = txID
				s.walSize = sz
				s.snapshotting = true
				s.reason = info.reason
			})
		if err := db.writeLTXFromDB(ctx, enc, walFile, commit, pageMap); err != nil {
			if isDiskFullError(err) {
				return result, NewLTXError("stage-write", tmpFilename, 0, uint64(txID), uint64(txID), fmt.Errorf("%w: %w", ErrDiskFull, err))
			}
			return result, fmt.Errorf("write ltx from db: %w", err)
		}
	} else {
		db.setSyncDiagPhase(diagPhaseWriteLTXFromWAL,
			func(s *diagState) {
				s.txID = txID
				s.walSize = sz
				s.snapshotting = false
				s.reason = info.reason
			})
		if err := db.writeLTXFromWAL(ctx, enc, walFile, info.prevCommit, commit, pageMap); err != nil {
			if isDiskFullError(err) {
				return result, NewLTXError("stage-write", tmpFilename, 0, uint64(txID), uint64(txID), fmt.Errorf("%w: %w", ErrDiskFull, err))
			}
			return result, fmt.Errorf("write ltx from wal: %w", err)
		}
	}

	// Encode final trailer to the end of the LTX file.

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Verify DB integrity: run `sqlite3 <db> 'PRAGMA integrity_check;'` and check the WAL file is intact.
  2. Ensure only litestream manages the database files — stop tools that copy/rotate the db or WAL.
  3. Check dmesg for read I/O errors on the database volume.
  4. Re-run replication; if local LTX state is broken, `litestream reset` for the database.
  5. Ensure litestream is not being stopped/restarted mid-snapshot (init system restart loops).

Example fix

// before: nightly rsync job copies db + wal while litestream runs
0 * * * * rsync -a /data/app.db /backup/
// after: use sqlite backup or litestream restore instead
0 * * * * litestream restore -o /backup/app.db /data/app.db
Defensive patterns

Strategy: try-catch

Validate before calling

if err := sqliteIntegrityCheck(dbPath); err != nil {
    return fmt.Errorf("db corrupt, fix before replication: %w", err)
}
// integrity_check via sqlite3 CLI: sqlite3 db 'PRAGMA integrity_check;'

Try / catch

var le *os.PathError
if errors.As(err, &le) && errors.Is(le.Err, syscall.EIO) {
    log.Printf("read I/O error on %s during snapshot: %v", le.Path, le.Err)
    // check hardware, restore from backup, then reset
}

Prevention

When it happens

Trigger: Read errors on the database file or WAL file during page iteration (I/O error, file truncated/corrupted mid-copy), context cancellation from the caller, or an ltx encoder error propagating from page writes.

Common situations: Corrupt or externally modified DB/WAL files (another tool touching the SQLite files); storage failures on the DB volume; litestream shutdown mid-snapshot causing context cancellation.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/5af5cc1af70db024. Report an issue: GitHub.