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

  1. Check the wrapped error for replica upload failures and verify storage credentials/network connectivity to the replica backend.
  2. 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.
  3. Retry the sync after transient network errors; LTX uploads are idempotent per TXID.
  4. 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

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


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