benbjohnson/litestream · error

replica sync: %w

Error message

replica sync: %w

What it means

DB.SyncAndWait() wraps an error from the second stage, db.Replica.Sync(ctx), with "replica sync". This stage uploads local LTX files to the remote replica; failure means the remote replication (storage backend write) failed after the local sync succeeded.

Source

Thrown at db.go:725

	return SyncStatus{
		LocalTXID:  localPos.TXID,
		RemoteTXID: remotePos.TXID,
		InSync:     localPos.TXID > 0 && localPos.TXID == remotePos.TXID,
	}, nil
}

// SyncAndWait performs a full sync: WAL to LTX files, then LTX files to remote
// replica. Blocks until both stages complete.
func (db *DB) SyncAndWait(ctx context.Context) error {
	if db.Replica == nil {
		return fmt.Errorf("no replica configured")
	}

	if err := db.Sync(ctx); err != nil {
		return fmt.Errorf("db sync: %w", err)
	}
	if err := db.Replica.Sync(ctx); err != nil {
		return fmt.Errorf("replica sync: %w", err)
	}
	return nil
}

// EnsureExists restores the database from the configured replica if the local
// database file does not exist. If no backup is available, it returns nil and
// a fresh database will be created on Open(). Must be called before Open().
func (db *DB) EnsureExists(ctx context.Context) error {
	if db.Replica == nil {
		return fmt.Errorf("no replica configured")
	}
	if db.Replica.Client == nil {
		return fmt.Errorf("no replica client configured")
	}

	if _, err := os.Stat(db.Path()); err == nil {
		return nil
	} else if !os.IsNotExist(err) {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Unwrap the error to find the failing storage operation.
  2. Verify write permissions and credentials on the replica destination.
  3. Check for another litestream process replicating the same database (lease conflicts); stop duplicates.
  4. Retry on transient network errors — SyncAndWait is safe to call again; LTX uploads are idempotent per TXID.

Example fix

// before
if err := db.SyncAndWait(ctx); err != nil {
    return err // opaque
}
// after
if err := db.SyncAndWait(ctx); err != nil {
    if litestream.IsRetentionConflict(err) { /* handle lease conflict */ }
    return fmt.Errorf("sync and wait: %w", err) // keep chain for diagnosis
}
Defensive patterns

Strategy: retry

Validate before calling

// preflight a write to the replica destination with the same credentials
// before relying on SyncAndWait for critical paths

Try / catch

if err := db.SyncAndWait(ctx); err != nil {
    if isTransientNetwork(err) {
        time.Sleep(backoff)
        return db.SyncAndWait(ctx) // safe to retry
    }
    return err
}

Prevention

When it happens

Trigger: Calling db.SyncAndWait(ctx) when Replica.Sync fails: upload errors to S3/GCS/Azure/file storage, authentication failures, network timeouts, conditional-write (lease) conflicts with another litestream process, or the replica client not initialized.

Common situations: Expired cloud credentials; bucket permissions changed (PutObject denied); another replica process holding a lease (lease conflict); network partition during upload; misconfigured endpoint for S3-compatible providers (MinIO, R2).

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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