benbjohnson/litestream · warning

database already enabled: %s

Error message

database already enabled: %s

What it means

EnableDB refuses to start replication for a database whose DB object is already open (db.IsOpen() true). Enabling twice would double-start the monitor/replica loops, so the Store treats the second enable as an invalid state transition.

Source

Thrown at store.go:388

	if err := db.Close(ctx); err != nil {
		return fmt.Errorf("close db: %w", err)
	}

	return nil
}

// EnableDB starts replication for a registered database.
// The context is checked for cancellation before opening.
// Note: db.Open() itself does not support cancellation.
func (s *Store) EnableDB(ctx context.Context, path string) error {
	db := s.FindDB(path)
	if db == nil {
		return fmt.Errorf("database not found: %s", path)
	}

	if db.IsOpen() {
		return fmt.Errorf("database already enabled: %s", path)
	}

	// Check for cancellation before starting open
	if err := ctx.Err(); err != nil {
		return fmt.Errorf("enable database: %w", err)
	}

	if err := db.Open(); err != nil {
		return fmt.Errorf("open database: %w", err)
	}

	return nil
}

// DisableDB stops replication for a database.
func (s *Store) DisableDB(ctx context.Context, path string) error {
	db := s.FindDB(path)
	if db == nil {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check db.IsOpen() (or via IPC status) before calling EnableDB
  2. Treat this error as idempotent success if your goal is 'ensure enabled' — use errors.Is/string match on the message
  3. Serialize enable/disable calls through a single control path or mutex
  4. Use DisableDB before re-enabling if you need a restart

Example fix

// before
if err := store.EnableDB(ctx, path); err != nil { return err } // fails if already enabled
// after
if db := store.FindDB(path); db != nil && !db.IsOpen() {
    if err := store.EnableDB(ctx, path); err != nil { return err }
}
Defensive patterns

Strategy: validation

Validate before calling

if db := store.FindDB(path); db != nil && db.IsOpen() {
    return nil // already enabled, nothing to do
}

Try / catch

if err := store.EnableDB(ctx, path); err != nil {
    if strings.Contains(err.Error(), "already enabled") {
        return nil // treat as idempotent success
    }
    return err
}

Prevention

When it happens

Trigger: Calling Store.EnableDB(ctx, path) (IPC handleStart) on a DB that is already open — e.g. it was enabled earlier via IPC, or opened at startup by the config.

Common situations: Duplicate IPC 'start' commands (client retry, double-click in an operator UI); racing goroutines both calling EnableDB; assuming a DB was disabled when it was only paused.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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