benbjohnson/litestream · error

list WAL segments: %w

Error message

list WAL segments: %w

What it means

After selecting a snapshot, RestoreV3 fetches the WAL segment list for the snapshot's generation via client.WALSegmentsV3(ctx, snapshot.Generation); any backend error is wrapped as 'list WAL segments: %w'. WAL segments are needed to roll the snapshot forward to the latest transaction or requested timestamp.

Source

Thrown at replica.go:1126

	// Sort all snapshots by CreatedAt for timestamp-based selection.
	sortSnapshotsV3ByCreatedAt(allSnapshots)

	// Find best snapshot across all generations (latest, or before timestamp if specified).
	snapshot := findBestSnapshotV3(allSnapshots, opt.Timestamp)
	if snapshot == nil {
		return ErrNoSnapshots
	}

	r.Logger().Debug("selected v0.3.x snapshot",
		"generation", snapshot.Generation,
		"index", snapshot.Index,
		"created_at", snapshot.CreatedAt)

	// Get WAL segments for the snapshot's generation.
	segments, err := client.WALSegmentsV3(ctx, snapshot.Generation)
	if err != nil {
		return fmt.Errorf("list WAL segments: %w", err)
	}
	segments = filterWALSegmentsV3(segments, snapshot.Index, opt.Timestamp)

	r.Logger().Debug("found v0.3.x WAL segments", "n", len(segments))

	// Create parent directory if it doesn't exist.
	var dirInfo os.FileInfo
	if db := r.DB(); db != nil {
		dirInfo = db.DirInfo()
	}
	if err := internal.MkdirAll(filepath.Dir(opt.OutputPath), dirInfo); err != nil {
		return fmt.Errorf("create parent directory: %w", err)
	}

	// Create temp file for restore.
	tmpPath := opt.OutputPath + ".tmp"
	defer func() { _ = os.Remove(tmpPath) }()

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Inspect the wrapped cause for the specific storage error (auth, 404, timeout) and fix it
  2. Verify the WAL directory/prefix still exists in the snapshot's generation in the replica storage
  3. Check bucket lifecycle policies are not deleting WAL segments prematurely
  4. Retry the restore; listing is read-only and safe to repeat
Defensive patterns

Strategy: retry

Validate before calling

// preflight: WAL prefix must exist for the generation you expect to restore from
if _, err := client.WALSegmentsV3(ctx, generation); err != nil {
    return fmt.Errorf("WAL listing failed: %w", err)
}

Try / catch

if err := replica.Restore(ctx, opt); err != nil {
    if strings.Contains(err.Error(), "list WAL segments") {
        log.Printf("WAL listing failed, cause=%v", errors.Unwrap(err))
        return retryWithBackoff(ctx, 3, func() error { return replica.Restore(ctx, opt) })
    }
    return err
}

Prevention

When it happens

Trigger: Calling Replica.Restore when listing WAL objects fails — backend unreachable, wrong credentials, missing/g deleted WAL prefix for the selected generation, throttled list requests, or the storage layout is not v0.3.x compatible.

Common situations: WAL retention/lifecycle rules in the bucket deleted the WAL prefix while snapshots remain; S3 permissions differing between snapshot and WAL prefixes; network outage mid-restore; pointing at a bucket written by a different litestream version with an unexpected layout.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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