{"record":{"id":"32845c5ac855520a","repo":"benbjohnson/litestream","slug":"list-v0-3-x-snapshots-for-generation-s-w","errorCode":null,"errorMessage":"list v0.3.x snapshots for generation %s: %w","messagePattern":"list v0\\.3\\.x snapshots for generation (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replica.go","lineNumber":1383,"sourceCode":"\treturn nil\n}\n\n// findBestV3SnapshotForTimestamp returns the best v0.3.x snapshot for the given timestamp.\n// Returns nil if no suitable snapshot exists.\nfunc (r *Replica) findBestV3SnapshotForTimestamp(ctx context.Context, client ReplicaClientV3, timestamp time.Time) (*SnapshotInfoV3, error) {\n\tgenerations, err := client.GenerationsV3(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"list v0.3.x generations: %w\", err)\n\t}\n\tif len(generations) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tvar allSnapshots []SnapshotInfoV3\n\tfor _, gen := range generations {\n\t\tsnapshots, err := client.SnapshotsV3(ctx, gen)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"list v0.3.x snapshots for generation %s: %w\", gen, err)\n\t\t}\n\t\tallSnapshots = append(allSnapshots, snapshots...)\n\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.","sourceCodeStart":1365,"sourceCodeEnd":1401,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica.go#L1365-L1401","documentation":"Wraps an error returned by the replica client's SnapshotsV3 call while enumerating v0.3.x-format snapshots for each generation during v0.3.x restore candidate selection. The wrapped underlying error (network, storage backend, or listing failure) is preserved via %w. It indicates Litestream could not determine which v0.3.x snapshots exist, so timestamp-based format selection cannot proceed.","triggerScenarios":"Calling Restore (with a timestamp) on a replica whose storage backend fails the SnapshotsV3 listing: unreachable object store, deleted/missing generation directory, expired credentials, or a backend returning malformed listing results.","commonSituations":"S3/GCS/Azure credentials rotated or revoked; bucket renamed or region changed; v0.3.x replicas restored from a partial copy missing generation directories; network partition between Litestream and object storage.","solutions":["Check the wrapped cause (%w) for the storage backend error and verify connectivity/credentials with the storage CLI (e.g. aws s3 ls).","Verify the generation directories exist at the replica path and were fully migrated from v0.3.x.","Re-run Restore; if only v0.3.x listing is broken, force LTX restore by restoring from a v0.5+ replica.","If the backend is permanently broken, re-replicate to a new generation before restoring."],"exampleFix":"// before\nsnapshots, err := client.SnapshotsV3(ctx, gen)\nif err != nil {\n    return nil, fmt.Errorf(\"list v0.3.x snapshots for generation %s: %w\", gen, err)\n}\n// after\n// fix the cause: verify access before calling Restore\n// $ aws s3 ls s3://bucket/db/generations/\n// then retry:\nsnapshots, err := client.SnapshotsV3(ctx, gen)\nif err != nil {\n    return nil, fmt.Errorf(\"list v0.3.x snapshots for generation %s: %w\", gen, err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: pre-flight listing check before restore\nclient, err := replica.NewReplicaClientFromURL(replicaURL)\nif err != nil { return err }\ngens, err := client.Generations(ctx)\nif err != nil || len(gens) == 0 {\n    return fmt.Errorf(\"replica generations not listable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := restore(...); err != nil {\n    if strings.Contains(err.Error(), \"list v0.3.x snapshots\") {\n        // inspect wrapped cause, verify storage credentials, retry with backoff\n        return fmt.Errorf(\"v0.3.x listing failed, check backend access: %w\", err)\n    }\n    return err\n}","preventionTips":["Verify storage credentials and listing permissions before DR (run litestream ltx periodically).","Keep v0.3.x migration generations intact and fully copied.","Alert on object-store list errors in production."],"tags":["restore","v0-3-compat","storage-backend","snapshot-listing"],"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"}