{"record":{"id":"a341cc6a6a7d436d","repo":"benbjohnson/litestream","slug":"get-replica-position-w","errorCode":null,"errorMessage":"get replica position: %w","messagePattern":"get replica position: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":1599,"sourceCode":"}\n\n// checkDatabaseBehindReplica detects when a database has been restored to an\n// earlier state and the replica has a higher TXID. This handles issue #781.\n//\n// If detected, it clears local L0 files and fetches the latest L0 LTX file\n// from the replica to establish a baseline. The next DB.sync() will detect\n// the mismatch and trigger a snapshot at the current database state.\nfunc (db *DB) checkDatabaseBehindReplica(ctx context.Context) error {\n\t// Get database position from local L0 files\n\tdbPos, err := db.Pos()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get database position: %w\", err)\n\t}\n\n\t// Get replica position from remote\n\treplicaInfo, err := db.Replica.MaxLTXFileInfo(ctx, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get replica position: %w\", err)\n\t} else if replicaInfo.MaxTXID == 0 {\n\t\treturn nil // No remote replica data yet\n\t}\n\n\t// Check if database is behind replica\n\tif dbPos.TXID >= replicaInfo.MaxTXID {\n\t\treturn nil // Database is ahead or equal\n\t}\n\n\tdb.Logger.Info(\"detected database behind replica\",\n\t\t\"db_txid\", dbPos.TXID,\n\t\t\"replica_txid\", replicaInfo.MaxTXID)\n\n\t// Clear local L0 files\n\tl0Dir := db.LTXLevelDir(0)\n\tif err := os.RemoveAll(l0Dir); err != nil && !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"remove L0 directory: %w\", err)\n\t}","sourceCodeStart":1581,"sourceCodeEnd":1617,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L1581-L1617","documentation":"After reading the local position, checkDatabaseBehindReplica queries the replica's maximum LTX file info via db.Replica.MaxLTXFileInfo(ctx, 0). This error wraps any failure of that remote lookup. It means Litestream could not learn the replica's latest TXID, so the behind-check cannot proceed.","triggerScenarios":"checkDatabaseBehindReplica calls db.Replica.MaxLTXFileInfo(ctx, 0) and the replica client fails — network error to S3/GCS/Azure/file storage, missing credentials, bucket/container not found, or listing API failure at level 0.","commonSituations":"Replica storage credentials expired or wrong (S3 AccessDenied); network outage or DNS failure to the object store; bucket name/region misconfigured; storage backend temporarily returning 5xx; using a v0.3.x replica layout with a newer binary.","solutions":["Read the wrapped (%w) cause in the log to identify transport vs auth vs listing failure.","Verify replica credentials and bucket/container access (aws s3 ls s3://bucket/path or equivalent).","Check network/DNS/proxy reachability to the replica endpoint.","Retry — object-store listing failures are often transient; Litestream will re-run the check on the next sync."],"exampleFix":"// before: generic retry\nfor { db.checkDatabaseBehindReplica(ctx) }\n// after: inspect wrapped cause first\nif err := db.checkDatabaseBehindReplica(ctx); err != nil {\n    log.Printf(\"behind-check failed: %v\", err) // surfaces \"get replica position: AccessDenied\"\n}","handlingStrategy":"retry","validationCode":"// Verify replica reachability/credentials before starting\n_, err := client.ListLTXFiles(ctx, 0)\nif err != nil { log.Fatalf(\"replica unreachable: %v\", err) }","typeGuard":"null","tryCatchPattern":"if err := run(); err != nil {\n    var retryable = errors.Is(err, context.DeadlineExceeded) || isNetworkErr(err)\n    if retryable { time.Sleep(backoff); retry() }\n}","preventionTips":["Rotate credentials before expiry and test with the storage CLI","Set sane timeouts and check-interval so transient failures are retried","Verify bucket/region config with a manual list call","Alert on replica position read failures in monitoring"],"tags":["litestream","replica","network","object-storage"],"backgroundTag":"http-error-response","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"}