benbjohnson/litestream · error
%w: %s
Error message
%w: %s
What it means
SyncDB resolves the database by path and returns a wrapped sentinel: fmt.Errorf("%w: %s", ErrDatabaseNotFound, path). Unlike EnableDB/DisableDB, this uses a sentinel error so callers can match it with errors.Is. It means no registered DB corresponds to the given path.
Source
Thrown at store.go:436
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,
// only performs the WAL-to-LTX sync and lets the replica monitor handle upload.
// Lock waits are context-aware: the timeout is honored while waiting for
// the database sync executor and the replica sync lock.
func (s *Store) SyncDB(ctx context.Context, path string, wait bool) (SyncDBResult, error) {
db := s.FindDB(path)
if db == nil {
return SyncDBResult{}, fmt.Errorf("%w: %s", ErrDatabaseNotFound, path)
}
if !db.IsOpen() {
return SyncDBResult{}, fmt.Errorf("%w: %s", ErrDatabaseNotOpen, path)
}
_, beforeTXID, err := db.MaxLTX()
if err != nil {
return SyncDBResult{}, fmt.Errorf("read position before sync: %w", err)
}
if wait {
if err := db.SyncAndWait(ctx); err != nil {
return SyncDBResult{}, fmt.Errorf("sync database: %w", err)
}
} else {
if err := db.Sync(ctx); err != nil {
return SyncDBResult{}, fmt.Errorf("sync database: %w", err)View on GitHub (pinned to 4ed7a308f6)
Solutions
- Check errors.Is(err, ErrDatabaseNotFound) to distinguish lookup failure from sync failure
- Resolve and pass the exact registered path (filepath.Abs/Clean, same as config)
- Query the store/IPC for registered DB paths before issuing a sync
- Register the database first if it is expected to exist
Example fix
// before
_, err := store.SyncDB(ctx, "app.db", true) // sentinel lost on generic match
// after
abs, _ := filepath.Abs("app.db")
if _, err := store.SyncDB(ctx, abs, true); err != nil {
if errors.Is(err, ErrDatabaseNotFound) { /* handle missing db */ }
} Defensive patterns
Strategy: validation
Validate before calling
abs, err := filepath.Abs(path)
if err != nil { return err }
if store.FindDB(abs) == nil {
return fmt.Errorf("db not registered: %s", abs)
} Try / catch
if _, err := store.SyncDB(ctx, abs, wait); err != nil {
if errors.Is(err, ErrDatabaseNotFound) {
// lookup failure: fix path or register db
} else if errors.Is(err, ErrDatabaseNotOpen) {
// enable first
}
return err
} Prevention
- Always match SyncDB errors with errors.Is against the exported sentinels
- Normalize paths before calling store APIs
- Keep config, registration, and IPC paths identical
When it happens
Trigger: Store.SyncDB(ctx, path, wait) (IPC handleSync) with a path not present in the Store's registry.
Common situations: IPC sync requests using a path spelling that differs from the configured one (relative path, symlink, trailing slash); syncing after the DB was unregistered or removed during a config reload.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- database not found: %s
- database already exists, skipping
- open database: %w
- open database: %w
- set journal mode: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/6d81b1dccdc32cd6.
Report an issue: GitHub.