benbjohnson/litestream · error

store required

Error message

store required

What it means

NewDirectoryMonitor requires a non-nil *litestream.Store to attach the monitored databases to. This error is returned when the store parameter is nil, because the monitor has nowhere to register newly discovered databases. Like the dbc check, it is a constructor guard against invalid arguments.

Source

Thrown at cmd/litestream/directory_watcher.go:52

	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
	}

	monitorCtx, cancel := context.WithCancel(ctx)
	dm := &DirectoryMonitor{

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Create and open the *litestream.Store before calling NewDirectoryMonitor, and pass the resulting pointer.
  2. Check the error/return of the code that built the store — a nil store usually means an earlier failure was swallowed.
  3. If store creation failed, abort startup instead of continuing with a nil store.

Example fix

// before
store, err := litestream.NewStore(cfg) // err ignored
mon, err := NewDirectoryMonitor(ctx, store, dbc, existing)
// after
store, err := litestream.NewStore(cfg)
if err != nil {
    return err
}
if err := store.Open(); err != nil {
    return err
}
mon, err := NewDirectoryMonitor(ctx, store, dbc, existing)
Defensive patterns

Strategy: type-guard

Validate before calling

if store == nil {
    return errors.New("store must be created and opened before starting the directory monitor")
}

Type guard

func storeReady(s *litestream.Store) bool { return s != nil }

Try / catch

mon, err := litestream.NewDirectoryMonitor(ctx, store, dbc, existing)
if err != nil {
    if err.Error() == "store required" {
        return fmt.Errorf("store not initialized: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling litestream.NewDirectoryMonitor(ctx, nil, dbc, existing) — typically when Store initialization failed earlier or was skipped, and the nil store was still passed to the monitor constructor.

Common situations: Embedding litestream where NewStore/Open failed or returned nil and the error was ignored; starting the directory monitor before the store is created; refactoring that reordered store creation after monitor startup.

Related errors


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