benbjohnson/litestream · warning

database already disabled: %s

Error message

database already disabled: %s

What it means

DisableDB refuses to close a database that is not currently open (db.IsOpen() false). Closing an already-disabled DB would be a no-op at best and a state bug at worst, so the Store reports it as an invalid state transition.

Source

Thrown at store.go:411

		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 {
		return fmt.Errorf("database not found: %s", path)
	}

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

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

	return nil
}

// SyncDBResult holds the result of a sync operation.
type SyncDBResult struct {
	TXID           uint64
	ReplicatedTXID uint64
	Changed        bool
}

// SyncDB forces an immediate sync for a database. If wait is true, blocks
// until both WAL-to-LTX and LTX-to-remote sync complete. If wait is false,

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check db.IsOpen() before calling DisableDB and skip if already closed
  2. Treat this as idempotent success when the desired end state is 'disabled'
  3. Serialize enable/disable operations through one control loop
  4. Re-check state after concurrent operations rather than assuming the DB is open

Example fix

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

Strategy: validation

Validate before calling

if db := store.FindDB(path); db == nil || !db.IsOpen() {
    return nil // already disabled or absent
}

Try / catch

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

Prevention

When it happens

Trigger: Store.DisableDB(ctx, path) on a DB that was registered but never opened, or already disabled by a previous DisableDB call.

Common situations: Duplicate 'stop' IPC commands from retries; stopping a DB that failed to open earlier; racing two operators disabling the same database.

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/f14819dd03dd8c7f. Report an issue: GitHub.