benbjohnson/litestream · error
v0.3.x time bounds: %w
Error message
v0.3.x time bounds: %w
What it means
When the replica client supports the legacy v0.3.x format (ReplicaClientV3), CalcRestoreTarget also computes time bounds from old-generation backups via TimeBoundsV3. Failure of that legacy enumeration is wrapped with this message, separate from the current-format 'created at' error, so you know which backup format's metadata could not be read.
Source
Thrown at replica.go:573
return createdAt, updatedAt, err
}
}
return createdAt, updatedAt, nil
}
// CalcRestoreTarget returns a target time restore from.
func (r *Replica) CalcRestoreTarget(ctx context.Context, opt RestoreOptions) (updatedAt time.Time, err error) {
// Determine the replicated time bounds from LTX files.
createdAt, updatedAt, err := r.TimeBounds(ctx)
if err != nil {
return time.Time{}, fmt.Errorf("created at: %w", err)
}
// Also check v0.3.x time bounds if client supports it.
if client, ok := r.Client.(ReplicaClientV3); ok {
v3CreatedAt, v3UpdatedAt, err := r.TimeBoundsV3(ctx, client)
if err != nil {
return time.Time{}, fmt.Errorf("v0.3.x time bounds: %w", err)
}
// Extend time bounds to include v0.3.x backups.
if !v3CreatedAt.IsZero() && (createdAt.IsZero() || v3CreatedAt.Before(createdAt)) {
createdAt = v3CreatedAt
}
if !v3UpdatedAt.IsZero() && (updatedAt.IsZero() || v3UpdatedAt.After(updatedAt)) {
updatedAt = v3UpdatedAt
}
}
// Skip if it does not contain timestamp.
if !opt.Timestamp.IsZero() {
if createdAt.IsZero() && updatedAt.IsZero() {
return time.Time{}, fmt.Errorf("no backups found")
}
if opt.Timestamp.Before(createdAt) || opt.Timestamp.After(updatedAt) {
return time.Time{}, fmt.Errorf("timestamp does not exist")
}View on GitHub (pinned to 4ed7a308f6)
Solutions
- Read the wrapped cause to see which legacy generation/metadata read failed.
- If legacy v0.3.x backups are no longer needed, remove the legacy generations or use a client without ReplicaClientV3 support so they are skipped.
- Restore access to / re-upload intact legacy objects, or rely on current LTX backups only.
- Run `litestream ltx` to verify what the replica can currently see.
Defensive patterns
Strategy: try-catch
Validate before calling
// detect legacy support before relying on v0.3.x bounds
if _, ok := replica.Client.(litestream.ReplicaClientV3); ok {
// legacy metadata will be read; validate legacy generations exist
} Type guard
if v3, ok := replica.Client.(litestream.ReplicaClientV3); ok {
// client supports legacy format
} Try / catch
target, err := replica.CalcRestoreTarget(ctx, opt)
if err != nil && strings.Contains(err.Error(), "v0.3.x time bounds") {
// legacy metadata unreadable: decide whether legacy backups are still needed
} Prevention
- After migrating from v0.3.x, either keep legacy generations intact or remove them deliberately
- Don't manually prune generation directories in replica storage
- Test restores after version upgrades
When it happens
Trigger: CalcRestoreTarget is called on a replica whose Client implements ReplicaClientV3, and TimeBoundsV3 fails reading legacy generation metadata (missing/invalid generations, listing errors, unreadable legacy super-records).
Common situations: Replicas upgraded from litestream v0.3.x with partially deleted or damaged legacy _ generations; storage listing failures; legacy timestamps records missing or corrupted after manual storage cleanup.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- invalid -timestamp, must specify in ISO 8601 format (e.g. 20
- database already exists, skipping
- no snapshots available
- multiple replicas on a single database are no longer support
- replica path cannot be a url, please use the 'url' field ins
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/c62255788315e73e.
Report an issue: GitHub.