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

  1. Check errors.Is(err, ErrDatabaseNotFound) to distinguish lookup failure from sync failure
  2. Resolve and pass the exact registered path (filepath.Abs/Clean, same as config)
  3. Query the store/IPC for registered DB paths before issuing a sync
  4. 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

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


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/6d81b1dccdc32cd6. Report an issue: GitHub.