benbjohnson/litestream · warning

create temp meta file

Error message

create temp meta file: %w

What it means

Hydrator.saveMeta wraps os.CreateTemp failures in the meta file's directory as "create temp meta file". saveMeta persists the current TXID atomically by writing a temp file and renaming it; if a temp file cannot be created, the meta save aborts (litestream logs a warning and continues, since hydration resume is best-effort).

Solutions

  1. Verify the directory containing the hydration file is writable by the litestream user (ls -ld, check uid)
  2. Free disk space / check inode usage (df -i)
  3. Do not point the hydration path at a read-only or ephemeral volume
  4. Note: saveMeta failures only cost hydration-resume on restart — fix the filesystem, restart litestream to re-hydrate
Defensive patterns

Strategy: validation

Validate before calling

// ensure the meta directory is writable before opening the VFS
dir := filepath.Dir(hydrationPath)
probe, err := os.CreateTemp(dir, ".probe-*")
if err != nil {
	// fix permissions/ownership before starting litestream
} else {
	probe.Close(); os.Remove(probe.Name())
}

Prevention

When it happens

Trigger: Creating .hydration-meta-* in the hydration directory fails because the directory was deleted, is read-only, or lacks write permission; the filesystem is full (temp inode creation can still fail on some systems); path is on a read-only remount.

Common situations: Container running as non-root writing to a root-owned directory; hydration path pointing at a read-only volume; the hydration directory removed by a cleaner while litestream runs.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


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

Appendix: source

Thrown at vfs.go:989

	if err != nil {
		return 0, err
	}
	v, err := strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
	if err != nil {
		return 0, fmt.Errorf("parse hydration meta: %w", err)
	}
	return ltx.TXID(v), nil
}

func (h *Hydrator) saveMeta() error {
	h.mu.Lock()
	txid := h.txid
	h.mu.Unlock()

	dir := filepath.Dir(h.metaPath())
	tmp, err := os.CreateTemp(dir, ".hydration-meta-*")
	if err != nil {
		return fmt.Errorf("create temp meta file: %w", err)
	}
	tmpPath := tmp.Name()

	if _, err := fmt.Fprintf(tmp, "%d\n", txid); err != nil {
		if closeErr := tmp.Close(); closeErr != nil {
			h.logger.Warn("failed to close temp meta file during cleanup", "error", closeErr)
		}
		if removeErr := os.Remove(tmpPath); removeErr != nil {
			h.logger.Warn("failed to remove temp meta file during cleanup", "error", removeErr)
		}
		return fmt.Errorf("write hydration meta: %w", err)
	}
	if err := tmp.Sync(); err != nil {
		if closeErr := tmp.Close(); closeErr != nil {
			h.logger.Warn("failed to close temp meta file during cleanup", "error", closeErr)
		}
		if removeErr := os.Remove(tmpPath); removeErr != nil {
			h.logger.Warn("failed to remove temp meta file during cleanup", "error", removeErr)

View on GitHub (pinned to 4ed7a308f6)