benbjohnson/litestream · error

start directory monitor for %s: %w

Error message

start directory monitor for %s: %w

What it means

Directory monitors watch configured directories for new SQLite databases and register them with the store. When starting a monitor fails (e.g. the directory does not exist or cannot be watched), Run closes already-started monitors and the store, then returns this error naming the offending directory.

Source

Thrown at cmd/litestream/replicate.go:321

		c.Server.SocketPath = c.Config.Socket.Path
		c.Server.SocketPerms = c.Config.Socket.Permissions
		c.Server.PathExpander = expand
		c.Server.Version = Version
		if err := c.Server.Start(); err != nil {
			slog.Warn("failed to start control server", "error", err)
		}
	}

	for _, entry := range watchables {
		monitor, err := NewDirectoryMonitor(ctx, c.Store, entry.config, entry.dbs)
		if err != nil {
			for _, m := range c.directoryMonitors {
				m.Close()
			}
			if closeErr := c.Store.Close(ctx); closeErr != nil {
				slog.Error("failed to close store after monitor failure", "error", closeErr)
			}
			return fmt.Errorf("start directory monitor for %s: %w", entry.config.Dir, err)
		}
		c.directoryMonitors = append(c.directoryMonitors, monitor)
	}

	// Notify user that initialization is done.
	for _, db := range c.Store.DBs() {
		r := db.Replica
		slog.Info("initialized db", "path", db.Path())
		slogWith := slog.With("type", r.Client.Type(), "sync-interval", r.SyncInterval)
		switch client := r.Client.(type) {
		case *file.ReplicaClient:
			slogWith.Info("replicating to", "path", client.Path())
		case *s3.ReplicaClient:
			slogWith.Info("replicating to", "bucket", client.Bucket, "path", client.Path, "region", client.Region, "endpoint", client.Endpoint)
		case *gs.ReplicaClient:
			slogWith.Info("replicating to", "bucket", client.Bucket, "path", client.Path)
		case *abs.ReplicaClient:
			slogWith.Info("replicating to", "bucket", client.Bucket, "path", client.Path, "endpoint", client.Endpoint)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check the directory path in the error exists and is readable before starting litestream
  2. Fix the config entry for the directory monitor (remove or correct the path)
  3. Ensure the volume/directory is mounted in containerized deployments before startup
  4. Raise fs.inotify.max_user_watches/max_user_instances if watcher limits are the cause

Example fix

// before (config)
monitor:
  - dir: /data/dbs
// after
# verify path exists
mkdir -p /data/dbs && litestream replicate -config litestream.yml
Defensive patterns

Strategy: validation

Validate before calling

# ensure all monitored dirs exist and are readable before start
for d in $(yq '.monitor[].dir' litestream.yml); do
  [ -d "$d" ] && [ -r "$d" ] || { echo "bad monitor dir: $d" >&2; exit 1; }
done

Try / catch

if err := cmd.Run(ctx); err != nil {
    if strings.Contains(err.Error(), "start directory monitor") {
        // extract dir from message, alert on config/volume problem
    }
    return err
}

Prevention

When it happens

Trigger: Config contains a directory monitor entry (`dir:` style config); the monitored path doesn't exist, isn't readable, or the filesystem watcher cannot be initialized. `monitor.Start(ctx)` returns err at line ~321 of replicate.go.

Common situations: Typo in monitored directory path, directory created only after litestream starts, containers where the volume isn't mounted yet, inotify limits exhausted on Linux.

Related errors


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