benbjohnson/litestream · error

no replica configured

Error message

no replica configured

What it means

SyncStatus compares the local transaction position against the remote replica position, so it requires db.Replica to be configured. When the database was opened without a replica (local monitoring only), it returns the plain error 'no replica configured'.

Source

Thrown at db.go:694

func (db *DB) LastSuccessfulSyncAt() time.Time {
	db.lastSuccessfulSyncMu.RLock()
	defer db.lastSuccessfulSyncMu.RUnlock()
	return db.lastSuccessfulSyncAt
}

// SyncStatus represents the current replication state of the database.
type SyncStatus struct {
	LocalTXID  ltx.TXID
	RemoteTXID ltx.TXID
	InSync     bool
}

// SyncStatus returns the current replication status of the database, comparing
// the local transaction position against the remote replica position. The remote
// position is queried from the replica storage, so this method may perform I/O.
func (db *DB) SyncStatus(ctx context.Context) (SyncStatus, error) {
	if db.Replica == nil {
		return SyncStatus{}, fmt.Errorf("no replica configured")
	}

	localPos, err := db.Pos()
	if err != nil {
		return SyncStatus{}, fmt.Errorf("local position: %w", err)
	}

	remotePos, err := db.Replica.calcPos(ctx)
	if err != nil {
		return SyncStatus{}, fmt.Errorf("remote position: %w", err)
	}

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

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Add a replica section to the config for that database path and reload litestream
  2. Attach a replica programmatically before calling SyncStatus
  3. If the database is intentionally replica-less, guard the call: skip SyncStatus when db.Replica == nil and report a non-replicating status
  4. Verify the correct config file was loaded (a default/minimal config may omit replicas)

Example fix

// before
status, err := db.SyncStatus(ctx)
// after: guard when replication may be absent
if db.Replica == nil {
    return SyncStatusNotReplicating, nil
}
status, err := db.SyncStatus(ctx)
Defensive patterns

Strategy: type-guard

Validate before calling

// Check replica presence before calling SyncStatus
if db.Replica == nil {
    return SyncStatus{}, errors.New("db has no replica; skipping status check")
}

Type guard

func hasReplica(db *litestream.DB) bool { return db.Replica != nil }

Try / catch

if !hasReplica(db) {
    return SyncStatusNone, nil
}
status, err := db.SyncStatus(ctx)
if err != nil {
    return SyncStatusUnknown, fmt.Errorf("sync status: %w", err)
}

Prevention

When it happens

Trigger: Calling db.SyncStatus(ctx) (library API) on a DB opened without a replica attached — e.g. config file with no [[replica]] section for the database, or a Replica-less DB constructed programmatically.

Common situations: Deploying a config where a database block exists but replication was never configured (or was commented out); calling SyncStatus in monitoring code against a DB used only for restore; version changes where replicas became optional.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


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