benbjohnson/litestream · error
get replica position: %w
Error message
get replica position: %w
What it means
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.
Source
Thrown at db.go:1599
}
// checkDatabaseBehindReplica detects when a database has been restored to an
// earlier state and the replica has a higher TXID. This handles issue #781.
//
// If detected, it clears local L0 files and fetches the latest L0 LTX file
// from the replica to establish a baseline. The next DB.sync() will detect
// the mismatch and trigger a snapshot at the current database state.
func (db *DB) checkDatabaseBehindReplica(ctx context.Context) error {
// Get database position from local L0 files
dbPos, err := db.Pos()
if err != nil {
return fmt.Errorf("get database position: %w", err)
}
// Get replica position from remote
replicaInfo, err := db.Replica.MaxLTXFileInfo(ctx, 0)
if err != nil {
return fmt.Errorf("get replica position: %w", err)
} else if replicaInfo.MaxTXID == 0 {
return nil // No remote replica data yet
}
// Check if database is behind replica
if dbPos.TXID >= replicaInfo.MaxTXID {
return nil // Database is ahead or equal
}
db.Logger.Info("detected database behind replica",
"db_txid", dbPos.TXID,
"replica_txid", replicaInfo.MaxTXID)
// Clear local L0 files
l0Dir := db.LTXLevelDir(0)
if err := os.RemoveAll(l0Dir); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("remove L0 directory: %w", err)
}View on GitHub (pinned to 4ed7a308f6)
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.
Example fix
// before: generic retry
for { db.checkDatabaseBehindReplica(ctx) }
// after: inspect wrapped cause first
if err := db.checkDatabaseBehindReplica(ctx); err != nil {
log.Printf("behind-check failed: %v", err) // surfaces "get replica position: AccessDenied"
} Defensive patterns
Strategy: retry
Validate before calling
// Verify replica reachability/credentials before starting
_, err := client.ListLTXFiles(ctx, 0)
if err != nil { log.Fatalf("replica unreachable: %v", err) } Type guard
null
Try / catch
if err := run(); err != nil {
var retryable = errors.Is(err, context.DeadlineExceeded) || isNetworkErr(err)
if retryable { time.Sleep(backoff); retry() }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- open remote L0 file: %w
- copy L0 file: %w
- must specify replica for database
- cannot specify 'replica' and 'replicas' on a database
- multiple replicas on a single database are no longer support
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/a341cc6a6a7d436d.
Report an issue: GitHub.