benbjohnson/litestream · error
create hydration directory: %w
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.
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)
Solutions
- Create the parent directory manually and chown it to the process user (mkdir -p <dir> && chown app:app <dir>).
- Point hydrationPath at a location the process can write (e.g. a mounted writable volume in containers).
- Check that no path component is an existing regular file; rename or remove it.
- 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
- Provision and chown the hydration directory at deploy time.
- Point hydrationPath at a writable persistent volume, not a read-only mount.
- Ensure no path component collides with an existing file.
- Use the same user for all processes touching the hydration dir.
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
- create temp dir: %w
- open persistent hydration file: %w
- remove stale hydration meta: %w
- create hydration file: %w
- create parent directory: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/0a83809d89f5e3f1.
Report an issue: GitHub.