{"record":{"id":"1581358a118e3ce6","repo":"benbjohnson/litestream","slug":"database-already-enabled-s","errorCode":null,"errorMessage":"database already enabled: %s","messagePattern":"database already enabled: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"store.go","lineNumber":388,"sourceCode":"\n\tif err := db.Close(ctx); err != nil {\n\t\treturn fmt.Errorf(\"close db: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// EnableDB starts replication for a registered database.\n// The context is checked for cancellation before opening.\n// Note: db.Open() itself does not support cancellation.\nfunc (s *Store) EnableDB(ctx context.Context, path string) error {\n\tdb := s.FindDB(path)\n\tif db == nil {\n\t\treturn fmt.Errorf(\"database not found: %s\", path)\n\t}\n\n\tif db.IsOpen() {\n\t\treturn fmt.Errorf(\"database already enabled: %s\", path)\n\t}\n\n\t// Check for cancellation before starting open\n\tif err := ctx.Err(); err != nil {\n\t\treturn fmt.Errorf(\"enable database: %w\", err)\n\t}\n\n\tif err := db.Open(); err != nil {\n\t\treturn fmt.Errorf(\"open database: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// DisableDB stops replication for a database.\nfunc (s *Store) DisableDB(ctx context.Context, path string) error {\n\tdb := s.FindDB(path)\n\tif db == nil {","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/store.go#L370-L406","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check db.IsOpen() (or via IPC status) before calling EnableDB","Treat this error as idempotent success if your goal is 'ensure enabled' — use errors.Is/string match on the message","Serialize enable/disable calls through a single control path or mutex","Use DisableDB before re-enabling if you need a restart"],"exampleFix":"// before\nif err := store.EnableDB(ctx, path); err != nil { return err } // fails if already enabled\n// after\nif db := store.FindDB(path); db != nil && !db.IsOpen() {\n    if err := store.EnableDB(ctx, path); err != nil { return err }\n}","handlingStrategy":"validation","validationCode":"if db := store.FindDB(path); db != nil && db.IsOpen() {\n    return nil // already enabled, nothing to do\n}","typeGuard":null,"tryCatchPattern":"if err := store.EnableDB(ctx, path); err != nil {\n    if strings.Contains(err.Error(), \"already enabled\") {\n        return nil // treat as idempotent success\n    }\n    return err\n}","preventionTips":["Make enable/disable idempotent at the call site","Serialize control operations through one goroutine or mutex","Track desired vs actual DB state before issuing IPC commands"],"tags":["database","state","duplicate-operation"],"backgroundTag":"invalid-state-transition","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}