benbjohnson/litestream · error

replica client required before opening database

Error message

replica client required before opening database

What it means

DB.Open validates that db.Replica.Client is non-nil after checking the Replica itself. The Replica struct exists but carries no storage backend implementation, so Litestream cannot know where to replicate LTX files. Like the previous check, it is a fail-fast precondition enforced at open time.

Source

Thrown at db.go:785

}

// Open initializes the background monitoring goroutine.
func (db *DB) Open() (err error) {
	db.mu.Lock()
	if db.opened {
		db.mu.Unlock()
		return nil // already open
	}
	// Recreate context for fresh start (handles reopen after close)
	db.ctx, db.cancel = context.WithCancel(context.Background())
	db.mu.Unlock()

	// Validate fields on database.
	if db.Replica == nil {
		return fmt.Errorf("replica required before opening database")
	}
	if db.Replica.Client == nil {
		return fmt.Errorf("replica client required before opening database")
	}
	if db.MinCheckpointPageN <= 0 {
		return fmt.Errorf("minimum checkpoint page count required")
	}

	// Clear old temporary files that my have been left from a crash.
	if err := removeTmpFiles(db.metaPath); err != nil {
		return fmt.Errorf("cannot remove tmp files: %w", err)
	}

	// Set the compactor client once before starting any goroutines.
	db.compactor.VerifyCompaction = db.VerifyCompaction
	db.compactor.RetentionEnabled = db.RetentionEnabled
	db.compactor.client = db.Replica.Client

	// Start monitoring SQLite database in a separate goroutine.
	if db.MonitorInterval > 0 {
		db.wg.Add(1)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Assign a concrete replica client, e.g. db.Replica.Client = s3.NewReplicaClient() with its fields set.
  2. For config-driven setups, verify the replica type in YAML maps to a registered backend and the client is built during config parsing.
  3. Log/inspect the Replica object right before Open() to confirm Client != nil.

Example fix

// before
db.Replica = litestream.NewReplica(db, "s3")
if err := db.Open(); err != nil { ... }
// after
db.Replica = litestream.NewReplica(db, "s3")
rc := s3.NewReplicaClient()
rc.Bucket, rc.Path, rc.Region = "my-bucket", "db", "us-east-1"
db.Replica.Client = rc
if err := db.Open(); err != nil { ... }
Defensive patterns

Strategy: validation

Validate before calling

if db.Replica != nil && db.Replica.Client == nil {
    return fmt.Errorf("replica %s: client backend not configured", db.Replica.Name())
}

Prevention

When it happens

Trigger: Setting db.Replica = litestream.NewReplica(...) but never assigning db.Replica.Client; creating a Replica whose Client field was cleared or not deserialized from config.

Common situations: Library users wiring a replica manually and forgetting the backend client (S3, GCS, SFTP, file, etc.); custom ReplicaClient implementations assigned incorrectly; config parsing that created the replica but failed to instantiate the client silently.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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