benbjohnson/litestream · error

database config required

Error message

database config required

What it means

NewDirectoryMonitor constructs a monitor for directory-based replication and requires a non-nil *DBConfig describing the database directory to watch. This error is returned immediately when the dbc parameter is nil, because without a DBConfig the monitor cannot determine which directory to watch or which database to manage. It is a programmer-error guard against calling the constructor with incomplete arguments.

Source

Thrown at cmd/litestream/directory_watcher.go:49

	cancel  context.CancelFunc

	logger *slog.Logger

	mu          sync.Mutex
	dbs         map[string]*litestream.DB
	watchedDirs map[string]struct{}

	// Only accessed from the run() goroutine, so no mutex is needed.
	pendingEvents  map[string]fsnotify.Op
	debounceActive bool

	wg sync.WaitGroup
}

// NewDirectoryMonitor returns a new monitor for directory-based replication.
func NewDirectoryMonitor(ctx context.Context, store *litestream.Store, dbc *DBConfig, existing []*litestream.DB) (*DirectoryMonitor, error) {
	if dbc == nil {
		return nil, errors.New("database config required")
	}
	if store == nil {
		return nil, errors.New("store required")
	}

	dirPath, err := expand(dbc.Dir)
	if err != nil {
		return nil, err
	}

	if _, err := os.Stat(dirPath); err != nil {
		return nil, err
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Ensure the *DBConfig passed to NewDirectoryMonitor is non-nil; construct one with at least Dir set to the database directory path.
  2. Check upstream config parsing (where DBConfig is built) to see why it produced nil; log/skip nil entries before calling NewDirectoryMonitor.
  3. If the config has no directory-based DB, do not call NewDirectoryMonitor at all instead of passing nil.

Example fix

// before
mon, err := NewDirectoryMonitor(ctx, store, cfg.DB, existing)
// after
if cfg.DB == nil {
    return fmt.Errorf("no db config configured for directory monitor")
}
mon, err := NewDirectoryMonitor(ctx, store, cfg.DB, existing)
Defensive patterns

Strategy: type-guard

Validate before calling

if dbc == nil {
    return errors.New("directory monitor requires a DBConfig with Dir set")
}
if dbc.Dir == "" {
    return errors.New("DBConfig.Dir must be set")
}

Type guard

func validMonitorArgs(store *litestream.Store, dbc *litestream.DBConfig) bool {
    return store != nil && dbc != nil && dbc.Dir != ""
}

Try / catch

mon, err := litestream.NewDirectoryMonitor(ctx, store, dbc, existing)
if err != nil {
    if err.Error() == "database config required" {
        // dbc was nil: fix config loading before retry
    }
    return fmt.Errorf("directory monitor: %w", err)
}

Prevention

When it happens

Trigger: Calling litestream.NewDirectoryMonitor(ctx, store, nil, existing) with a nil *DBConfig, e.g. when DB config parsing silently produced no config or a loop over configs skipped initialization and passed a nil entry.

Common situations: Building a custom embedding of litestream where DBConfig is conditionally populated (e.g. only set when a 'dir' key exists in user config) and the nil case is passed through; refactoring code that used to construct DBConfig unconditionally; misparsing TOML/YAML config so the dbs entry yields a nil config.

Related errors


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