benbjohnson/litestream · error

create hydration file: %w

Error message

create hydration file: %w

What it means

After any stale state is cleared, Hydrator.Init creates/opens the hydration database file with os.OpenFile(path, O_RDWR|O_CREATE|O_TRUNC, 0600). This error wraps that failure. It is the final and most common step of hydration initialization, so any file-creation problem in the hydration directory surfaces here.

Source

Thrown at vfs.go:703

		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)
		}
	}

	file, err := os.OpenFile(h.path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return fmt.Errorf("create hydration file: %w", err)
	}
	h.file = file
	return nil
}

// Complete returns true if hydration has completed.
func (h *Hydrator) Complete() bool {
	return h.complete.Load()
}

// SetComplete marks hydration as complete.
func (h *Hydrator) SetComplete() {
	h.complete.Store(true)
}

// Disable temporarily disables hydrated reads (used during time travel).
func (h *Hydrator) Disable() {
	h.complete.Store(false)

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check free space on the filesystem of the hydration path (df -h) and free or expand it.
  2. Ensure the hydration directory is writable by the process user and that hydrationPath names a file, not a directory.
  3. Confirm no MAC policy (SELinux/AppArmor) blocks file creation there; check audit logs.
  4. Point hydrationPath at a dedicated writable volume sized for the database.

Example fix

// before
hydrator := NewHydrator("/mnt/ro-vol/hydration.db") // read-only mount

// after
hydrator := NewHydrator("/mnt/writable-vol/hydration.db") // rw mount with free space
Defensive patterns

Strategy: validation

Validate before calling

p := hydrator.Path()
if fi, err := os.Stat(p); err == nil && fi.IsDir() {
    return fmt.Errorf("hydration path %q is a directory", p)
}
if err := unix.Access(filepath.Dir(p), unix.W_OK); err != nil {
    return fmt.Errorf("hydration dir not writable: %w", err)
}

Try / catch

if err := hydrator.Init(); err != nil && strings.Contains(err.Error(), "create hydration file") {
    // check disk space (ENOSPC), perms, and that path is not a directory
}

Prevention

When it happens

Trigger: Init on a fresh or cleared hydrator where the hydration file cannot be created — directory permissions deny write, disk full, path exceeds NAME_MAX, or the path exists as a directory.

Common situations: Disk-full on the volume holding the hydration path; hydrationPath accidentally pointing at a directory; SELinux denials on file creation; tiny ephemeral volumes filling up during hydration of large databases.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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