{"record":{"id":"313841ca333482d4","repo":"benbjohnson/litestream","slug":"get-v0-3-x-time-bounds-w","errorCode":null,"errorMessage":"get v0.3.x time bounds: %w","messagePattern":"get v0\\.3\\.x time bounds: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replica.go","lineNumber":1404,"sourceCode":"\t}\n\n\tif len(allSnapshots) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Sort by CreatedAt for timestamp-based selection.\n\tsortSnapshotsV3ByCreatedAt(allSnapshots)\n\n\treturn findBestSnapshotV3(allSnapshots, timestamp), nil\n}\n\n// shouldUseV3Restore determines whether to use v0.3.x restore instead of LTX.\n// Returns true if v0.3.x has a better backup for the given options.\nfunc (r *Replica) shouldUseV3Restore(ctx context.Context, client ReplicaClientV3, timestamp time.Time) (bool, error) {\n\t// Get v0.3.x time bounds.\n\t_, v3UpdatedAt, err := r.TimeBoundsV3(ctx, client)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"get v0.3.x time bounds: %w\", err)\n\t}\n\n\t// Get LTX time bounds.\n\t_, ltxUpdatedAt, err := r.TimeBounds(ctx)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"get LTX time bounds: %w\", err)\n\t}\n\n\t// If no v0.3.x backups exist, use LTX.\n\tif v3UpdatedAt.IsZero() {\n\t\treturn false, nil\n\t}\n\n\t// If no LTX backups exist, use v0.3.x.\n\tif ltxUpdatedAt.IsZero() {\n\t\tr.Logger().Debug(\"using v0.3.x restore (no LTX backups)\")\n\t\treturn true, nil\n\t}","sourceCodeStart":1386,"sourceCodeEnd":1422,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica.go#L1386-L1422","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before (caller sees wrapped error)\n_, v3UpdatedAt, err := r.TimeBoundsV3(ctx, client)\n// after\n// pre-flight check by the operator:\n// $ litestream replicas <db>   // confirm replica reachable\n// then re-run restore\n_, v3UpdatedAt, err := r.TimeBoundsV3(ctx, client)\nif err != nil {\n    return false, fmt.Errorf(\"get v0.3.x time bounds: %w\", err)\n}","handlingStrategy":"retry","validationCode":"// verify replica reachable before restore\nctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\ndefer cancel()\nif _, err := client.Generations(ctx); err != nil {\n    return fmt.Errorf(\"replica unreachable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := retry(3, backoff, func() error { _, err := restore(); return err })\nif err != nil && strings.Contains(err.Error(), \"get v0.3.x time bounds\") {\n    // transient backend failure; check IAM list permissions\n}","preventionTips":["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."],"tags":["restore","v0-3-compat","time-bounds","storage-backend"],"backgroundTag":"api-request-failed","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}