benbjohnson/litestream · error

write updated page %d: %w

Error message

write updated page %d: %w

What it means

Hydrator.ApplyUpdates wraps a failure writing a fetched page into the local hydration file as "write updated page %d". The page was successfully fetched from replica storage but the local pwrite at offset (pgno-1)*pageSize failed.

Source

Thrown at vfs.go:909

	}

	return n, nil
}

// ApplyUpdates fetches updated pages and writes them to the hydration file.
func (h *Hydrator) ApplyUpdates(ctx context.Context, updates map[uint32]ltx.PageIndexElem) error {
	h.mu.Lock()
	defer h.mu.Unlock()

	for pgno, elem := range updates {
		_, data, err := FetchPage(ctx, h.client, elem.Level, elem.MinTXID, elem.MaxTXID, elem.Offset, elem.Size)
		if err != nil {
			return fmt.Errorf("fetch updated page %d: %w", pgno, err)
		}

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

	return nil
}

// WritePage writes a single page to the hydration file.
func (h *Hydrator) WritePage(pgno uint32, data []byte) error {
	h.mu.Lock()
	defer h.mu.Unlock()

	off := int64(pgno-1) * int64(h.pageSize)
	if _, err := h.file.WriteAt(data, off); err != nil {
		return fmt.Errorf("write page %d to hydrated file: %w", pgno, err)
	}
	return nil
}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check disk free space on the hydration file's volume and expand if needed
  2. Check the wrapped os.PathError for which path/operation failed
  3. Confirm no external process is truncating or removing the hydration file
  4. Use litestream reset to rebuild the hydration file if it is in a bad state

Example fix

// diagnose offset & size
off := int64(pgno-1) * int64(h.pageSize)
if _, err := h.file.WriteAt(data, off); err != nil {
	return fmt.Errorf("write updated page %d at offset %d: %w", pgno, off, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure room for the hydrated DB before updating
if fi, err := os.Stat(hydrationPath); err == nil && fi.Size()+bytesNeeded > freeDisk(path) {
	// free space or enlarge volume first
}

Try / catch

if err := hydrator.ApplyUpdates(ctx, updates); err != nil {
	var pe *os.PathError
	if errors.As(err, &pe) && errors.Is(pe.Err, syscall.ENOSPC) {
		// free space / resize volume, then litestream reset
	}
}

Prevention

When it happens

Trigger: Disk full while writing the hydrated file; hydration file truncated or closed before ApplyUpdates; underlying storage I/O error; permission loss on the hydration file mid-run.

Common situations: Volume running out of space during heavy write workload; tmpfs hydration directory hitting size limits; disk removed or remounted read-only; file deleted by external cleanup jobs.

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