benbjohnson/litestream · error
close db: %w
Error message
close db: %w
What it means
UnregisterDB removes a database from the Store's registry and then closes it. This error wraps any failure returned by db.Close(ctx) during that teardown, so the DB may be unregistered but not fully shut down (WAL monitor, replicas, executors). Because it's a wrapped error, the underlying cause (e.g. replica close failure, context cancellation) is in the %w chain.
Source
Thrown at store.go:372
var db *DB
for i, existing := range s.dbs {
if existing.Path() == path {
idx = i
db = existing
break
}
}
if db == nil {
s.mu.Unlock()
return nil
}
s.dbs = slices.Delete(s.dbs, idx, idx+1)
s.mu.Unlock()
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)
}
View on GitHub (pinned to 4ed7a308f6)
Solutions
- Inspect the wrapped cause with errors.Unwrap / %v to see why Close failed
- Retry UnregisterDB once the in-flight sync completes; Close is retriable after the transient condition clears
- Pass a context with an adequate timeout instead of one already near cancellation
- Check replica/storage connectivity if the wrapped error points at replica cleanup
Example fix
// before
if err := db.Close(ctx); err != nil {
return fmt.Errorf("close db: %w", err)
}
// after
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := db.Close(ctx); err != nil {
return fmt.Errorf("close db: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if db := store.FindDB(path); db == nil {
return fmt.Errorf("db not registered: %s", path)
} Try / catch
if err := store.UnregisterDB(ctx, path); err != nil {
var ctxErr error
if errors.As(err, &ctxErr) && errors.Is(ctxErr, context.Canceled) {
// retry with fresh context
}
return fmt.Errorf("unregister %s: %w", path, err)
} Prevention
- Always pass a live context with sufficient timeout to UnregisterDB
- Avoid unregistering while syncs are in flight; drain first
- Log the full wrapped error chain, not just the top-level message
When it happens
Trigger: Calling Store.UnregisterDB(ctx, path) for a registered DB whose Close fails — e.g. db.Open() active, replica sync in flight, or ctx cancelled while close waits for locks.
Common situations: IPC-driven unregister (handleUnregister) or config reload (removeDatabase/removeDatabasesUnder) while the database is mid-sync; shutting down litestream with an open DB; cancelling the context passed to UnregisterDB during a slow close.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/b78644bdd9596c38.
Report an issue: GitHub.