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
- Check db.IsOpen() before calling DisableDB and skip if already closed
- Treat this as idempotent success when the desired end state is 'disabled'
- Serialize enable/disable operations through one control loop
- 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
- Check IsOpen before disable; skip if closed
- Centralize enable/disable state management to prevent races
- Design stop handlers to be idempotent
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
- database already enabled: %s
- open database: %w
- open database: %w
- set journal mode: %w
- create table %s: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/f14819dd03dd8c7f.
Report an issue: GitHub.