benbjohnson/litestream · error
sync database: %w
Error message
sync database: %w
What it means
The database sync itself failed inside Store.SyncDB when wait=true, i.e. db.SyncAndWait(ctx) returned an error. SyncAndWait runs db.Sync (WAL -> LTX) followed by db.Replica.Sync (upload to replica storage) and blocks until both finish, so this error indicates the WAL could not be synced or the replica could not be updated. The underlying cause is wrapped with %w.
Source
Thrown at store.go:450
// the database sync executor and the replica sync lock.
func (s *Store) SyncDB(ctx context.Context, path string, wait bool) (SyncDBResult, error) {
db := s.FindDB(path)
if db == nil {
return SyncDBResult{}, fmt.Errorf("%w: %s", ErrDatabaseNotFound, path)
}
if !db.IsOpen() {
return SyncDBResult{}, fmt.Errorf("%w: %s", ErrDatabaseNotOpen, path)
}
_, beforeTXID, err := db.MaxLTX()
if err != nil {
return SyncDBResult{}, fmt.Errorf("read position before sync: %w", err)
}
if wait {
if err := db.SyncAndWait(ctx); err != nil {
return SyncDBResult{}, fmt.Errorf("sync database: %w", err)
}
} else {
if err := db.Sync(ctx); err != nil {
return SyncDBResult{}, fmt.Errorf("sync database: %w", err)
}
}
_, afterTXID, err := db.MaxLTX()
if err != nil {
return SyncDBResult{}, fmt.Errorf("read position after sync: %w", err)
}
var replicatedTXID uint64
if db.Replica != nil {
replicatedTXID = uint64(db.Replica.Pos().TXID)
}
return SyncDBResult{View on GitHub (pinned to 4ed7a308f6)
Solutions
- Check the wrapped error for replica upload failures and verify storage credentials/network connectivity to the replica backend.
- If using wait=true with no replica, switch to wait=false or configure a replica; SyncAndWait errors with "no replica configured" when db.Replica is nil.
- Retry the sync after transient network errors; LTX uploads are idempotent per TXID.
- If db.Sync fails repeatedly, inspect the SQLite database/WAL health and run litestream reset if local LTX state is corrupted.
Example fix
// before
res, err := store.SyncDB(ctx, path, true)
if err != nil { return err }
// after
res, err := store.SyncDB(ctx, path, true)
if err != nil {
if errors.Is(err, litestream.ErrNoReplica) || strings.Contains(err.Error(), "no replica configured") {
return store.SyncDB(ctx, path, false) // local sync only
}
return err
} Defensive patterns
Strategy: retry
Validate before calling
// verify replica is configured before wait=true
if wait && replicaConfig == nil {
wait = false // or configure a replica
} Type guard
func hasReplica(db *litestream.DB) bool {
return db != nil && db.Replica != nil
} Try / catch
err := doSync()
if err != nil {
if isTransient(err) { // network/timeout errors
time.Sleep(backoff)
err = doSync()
}
if err != nil && strings.Contains(err.Error(), "no replica configured") {
return store.SyncDB(ctx, path, false)
}
return err
} Prevention
- Ensure a replica is configured when using wait=true
- Monitor storage credentials before expiry
- Retry syncs with exponential backoff on network errors
- Check DB and WAL health after abnormal shutdowns
When it happens
Trigger: SyncDB(ctx, path, true) where db.Sync fails (WAL read/checkpoint issue) or db.Replica.Sync fails (upload error); also SyncDB with wait=false where db.Sync fails.
Common situations: Replica storage credentials expired or bucket unavailable, network outage during upload, no replica configured while using SyncAndWait (returns "no replica configured"), or a corrupted WAL preventing checkpointing.
Related errors
- read position before sync: %w
- read position after sync: %w
- sync before disable: %w
- sync interval must be greater than 0
- cannot copy wal before checkpoint: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/4897956c64a7c7f1.
Report an issue: GitHub.