benbjohnson/litestream · error
get v0.3.x time bounds: %w
Error message
get v0.3.x time bounds: %w
What it means
Wraps an error from TimeBoundsV3 while deciding whether a v0.3.x restore should be used instead of LTX. Litestream needs the min/max timestamps of v0.3.x backups to compare them against LTX coverage; failure here aborts format selection. The underlying cause (listing or metadata read failure against the replica client) is preserved.
Source
Thrown at replica.go:1404
}
if len(allSnapshots) == 0 {
return nil, nil
}
// Sort by CreatedAt for timestamp-based selection.
sortSnapshotsV3ByCreatedAt(allSnapshots)
return findBestSnapshotV3(allSnapshots, timestamp), nil
}
// shouldUseV3Restore determines whether to use v0.3.x restore instead of LTX.
// Returns true if v0.3.x has a better backup for the given options.
func (r *Replica) shouldUseV3Restore(ctx context.Context, client ReplicaClientV3, timestamp time.Time) (bool, error) {
// Get v0.3.x time bounds.
_, v3UpdatedAt, err := r.TimeBoundsV3(ctx, client)
if err != nil {
return false, fmt.Errorf("get v0.3.x time bounds: %w", err)
}
// Get LTX time bounds.
_, ltxUpdatedAt, err := r.TimeBounds(ctx)
if err != nil {
return false, fmt.Errorf("get LTX time bounds: %w", err)
}
// If no v0.3.x backups exist, use LTX.
if v3UpdatedAt.IsZero() {
return false, nil
}
// If no LTX backups exist, use v0.3.x.
if ltxUpdatedAt.IsZero() {
r.Logger().Debug("using v0.3.x restore (no LTX backups)")
return true, nil
}View on GitHub (pinned to 4ed7a308f6)
Solutions
- Inspect the wrapped cause; confirm the storage credentials allow listing on the replica bucket/prefix.
- Retry the restore if the underlying error is transient (network/5xx).
- Verify v0.3.x replica data integrity; re-sync or re-replicate if generations are incomplete.
- If v0.3.x backups are not needed, remove the legacy replica data so the LTX path is used.
Example fix
// before (caller sees wrapped error)
_, v3UpdatedAt, err := r.TimeBoundsV3(ctx, client)
// after
// pre-flight check by the operator:
// $ litestream replicas <db> // confirm replica reachable
// then re-run restore
_, v3UpdatedAt, err := r.TimeBoundsV3(ctx, client)
if err != nil {
return false, fmt.Errorf("get v0.3.x time bounds: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// verify replica reachable before restore
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if _, err := client.Generations(ctx); err != nil {
return fmt.Errorf("replica unreachable: %w", err)
} Try / catch
err := retry(3, backoff, func() error { _, err := restore(); return err })
if err != nil && strings.Contains(err.Error(), "get v0.3.x time bounds") {
// transient backend failure; check IAM list permissions
} Prevention
- Grant ListObject/Read permissions on the whole replica prefix.
- Retry transient cloud errors with exponential backoff.
- Validate replica config with litestream check/dry runs before an actual DR event.
When it happens
Trigger: Restore triggers shouldUseV3Restore, which calls TimeBoundsV3; the client fails to enumerate or read v0.3.x backup metadata (network error, permission denied, corrupt generation listing).
Common situations: Object-store IAM policy lacks ListObjects on the replica prefix; v0.3.x-era replica directory contains partial/corrupt generation metadata; transient cloud outage during restore.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- list v0.3.x snapshots for generation %s: %w
- get LTX time bounds: %w
- created at: %w
- find v0.3.x snapshot: %w
- find LTX snapshots: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/313841ca333482d4.
Report an issue: GitHub.