benbjohnson/litestream · error

create hydration directory

Error message

create hydration directory: %w

What it means

Hydrator.Init creates the parent directory of the hydration file with os.MkdirAll before opening or creating the file. This error wraps that failure. Hydration stores a local materialized copy of the remote database, so its directory must exist and be writable before initialization can proceed.

Solutions

  1. Create the parent directory manually and chown it to the process user (mkdir -p <dir> && chown app:app <dir>).
  2. Point hydrationPath at a location the process can write (e.g. a mounted writable volume in containers).
  3. Check that no path component is an existing regular file; rename or remove it.
  4. If the mount is read-only, remount rw or select another directory.

Example fix

// before
hydrator := NewHydrator("/var/lib/litestream/hydration/app.db") // no permission

// after
os.MkdirAll("/var/lib/litestream/hydration", 0o755) // as setup step, with correct ownership
hydrator := NewHydrator("/var/lib/litestream/hydration/app.db")
Defensive patterns

Strategy: validation

Validate before calling

dir := filepath.Dir(hydrationPath)
if err := os.MkdirAll(dir, 0o755); err != nil {
    return fmt.Errorf("hydration dir %q not preparable: %w", dir, err)
}
probe, err := os.CreateTemp(dir, "probe-*")
if err != nil { return err }
probe.Close(); os.Remove(probe.Name())

Try / catch

if err := hydrator.Init(); err != nil && strings.Contains(err.Error(), "create hydration directory") {
    // fix ownership/permissions on dir, then retry Init
}

Prevention

When it happens

Trigger: Calling Hydrator.Init (via opening the DB with hydration enabled) when the directory containing the configured hydration path cannot be created — missing permission on the parent, path component is a file, or read-only filesystem.

Common situations: hydrationPath pointing under a read-only mount; typo making the parent path contain an existing file (e.g. /data/db where db is a file); running under a non-root container user with no write access to /var/lib/litestream.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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

Appendix: source

Thrown at vfs.go:681

	client     ReplicaClient
	logger     *slog.Logger
}

// NewHydrator creates a new Hydrator instance.
func NewHydrator(path string, persistent bool, pageSize uint32, client ReplicaClient, logger *slog.Logger) *Hydrator {
	return &Hydrator{
		path:       path,
		persistent: persistent,
		pageSize:   pageSize,
		client:     client,
		logger:     logger,
	}
}

// Init opens or creates the hydration file.
func (h *Hydrator) Init() error {
	if err := os.MkdirAll(filepath.Dir(h.path), 0755); err != nil {
		return fmt.Errorf("create hydration directory: %w", err)
	}

	if h.persistent {
		if txid, err := h.loadMeta(); err == nil {
			if _, statErr := os.Stat(h.path); statErr == nil {
				file, err := os.OpenFile(h.path, os.O_RDWR, 0600)
				if err != nil {
					return fmt.Errorf("open persistent hydration file: %w", err)
				}
				h.file = file
				h.txid = txid
				return nil
			}
		}
		if err := os.Remove(h.metaPath()); err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("remove stale hydration meta: %w", err)
		}
	}

View on GitHub (pinned to 4ed7a308f6)