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
- Inspect the wrapped cause for the specific storage error (auth, 404, timeout) and fix it
- Verify the WAL directory/prefix still exists in the snapshot's generation in the replica storage
- Check bucket lifecycle policies are not deleting WAL segments prematurely
- 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
- Check bucket lifecycle rules so WAL segments are not deleted before snapshots expire
- Grant the replica client credentials read access to both snapshot and WAL prefixes
- Keep litestream version consistent between writer and restore tooling to avoid layout mismatches
- Include WAL listing in pre-restore health checks
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
- list generations: %w
- list snapshots for generation %s: %w
- apply WAL segments: %w
- download snapshot: %w
- no snapshots available
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/f3eea4ce5af7fad4.
Report an issue: GitHub.