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
- Unwrap the error to find the failing storage operation.
- Verify write permissions and credentials on the replica destination.
- Check for another litestream process replicating the same database (lease conflicts); stop duplicates.
- 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
- Rotate and validate cloud credentials before expiry.
- Grant PutObject on the replica prefix to the litestream identity.
- Run exactly one litestream process per database to avoid lease conflicts.
- Retry SyncAndWait on transient errors — it is idempotent per TXID.
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
- remote position: %w
- fetch ltx files: %w
- cannot determine L%d max ltx file for %q: %w
- write ltx file: %w
- list level %d ltx files: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/7f4c00e664d2db50.
Report an issue: GitHub.