benbjohnson/litestream · error

write page %d: %w

Error message

write page %d: %w

What it means

applyLTXFile failed to write a decoded page into the local database file at the offset derived from the page number ((Pgno-1)*pageSize). This is a low-level file write failure (WriteAt) while reconstructing the database from the LTX transaction, and it aborts page application immediately to avoid a torn database.

Source

Thrown at replica.go:981

	defer internal.UnlockFile(f)

	for {
		var phdr ltx.PageHeader
		data := make([]byte, pageSize)
		if err := dec.DecodePage(&phdr, data); err == io.EOF {
			break
		} else if err != nil {
			return fmt.Errorf("decode page: %w", err)
		}

		if phdr.Pgno == 1 && len(data) >= 28 {
			data[18], data[19] = 0x01, 0x01
			_, _ = rand.Read(data[24:28])
		}

		off := int64(phdr.Pgno-1) * int64(pageSize)
		if _, err := f.WriteAt(data, off); err != nil {
			return fmt.Errorf("write page %d: %w", phdr.Pgno, err)
		}
	}

	if hdr.Commit > 0 {
		if err := f.Sync(); err != nil {
			return fmt.Errorf("sync before truncate: %w", err)
		}
		newSize := int64(hdr.Commit) * int64(pageSize)
		if err := f.Truncate(newSize); err != nil {
			return fmt.Errorf("truncate: %w", err)
		}
	}

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

	return f.Sync()

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Free disk space on the volume containing the database file
  2. Check filesystem/volume health (dmesg, fsck) and remount read-write if needed
  3. Verify the litestream process has write permission to the database path
  4. Retry the replication/restore after resolving the I/O condition

Example fix

# before
df -h /var/lib/db   # disk 100% full
# after
fstrim /var/lib/db && df -h /var/lib/db   # space freed, retry apply
Defensive patterns

Strategy: validation

Validate before calling

stat := syscall.Statfs_t{}
if err := syscall.Statfs(filepath.Dir(dbPath), &stat); err == nil {
    avail := stat.Bavail * uint64(stat.Bsize)
    if avail < 2*uint64(dbSizeHint) {
        return fmt.Errorf("insufficient disk space: %d bytes free", avail)
    }
}
if f, err := os.OpenFile(dbPath, os.O_WRONLY, 0); err != nil {
    return fmt.Errorf("db not writable: %w", err)
} else { f.Close() }

Try / catch

if err := r.applyLTXFile(ctx, f, info, pageSize); err != nil {
    if errors.Is(err, syscall.ENOSPC) || errors.Is(err, syscall.EIO) {
        // disk-full / IO: page ops team, do not blind-retry
        return fmt.Errorf("storage failure applying %s: %w", info.Path(), err)
    }
    return err
}

Prevention

When it happens

Trigger: os.File.WriteAt fails for page phdr.Pgno: disk full, I/O error on the database volume, file descriptor/permission problems on the DB path, or a write offset beyond filesystem limits.

Common situations: Disk full on the host holding the SQLite database, failing or read-only-remounted volumes, Docker/Kubernetes volume exhaustion, NFS/EFS transient I/O errors during restore.

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