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

  1. Read the wrapped (%w) cause in the log to identify transport vs auth vs listing failure.
  2. Verify replica credentials and bucket/container access (aws s3 ls s3://bucket/path or equivalent).
  3. Check network/DNS/proxy reachability to the replica endpoint.
  4. 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

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


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/a341cc6a6a7d436d. Report an issue: GitHub.