benbjohnson/litestream · error

create temp L0 file: %w

Error message

create temp L0 file: %w

What it means

The fetched remote L0 LTX file is first written to a temp file (localPath + ".tmp"). This error wraps os.Create failing on that temp path, meaning Litestream could not create the staging file in the L0 directory.

Source

Thrown at db.go:1637

	if err := internal.MkdirAll(l0Dir, db.dirInfo); err != nil {
		return fmt.Errorf("recreate L0 directory: %w", err)
	}

	// Fetch latest L0 LTX file from replica
	minTXID, maxTXID := replicaInfo.MinTXID, replicaInfo.MaxTXID
	reader, err := db.Replica.Client.OpenLTXFile(ctx, 0, minTXID, maxTXID, 0, 0)
	if err != nil {
		return fmt.Errorf("open remote L0 file: %w", err)
	}
	defer func() { _ = reader.Close() }()

	// Write to temp file and atomically rename
	localPath := db.LTXPath(0, minTXID, maxTXID)
	tmpPath := localPath + ".tmp"

	tmpFile, err := os.Create(tmpPath)
	if err != nil {
		return fmt.Errorf("create temp L0 file: %w", err)
	}
	defer func() { _ = os.Remove(tmpPath) }() // Clean up temp file on error

	if _, err := io.Copy(tmpFile, reader); err != nil {
		_ = tmpFile.Close()
		return fmt.Errorf("copy L0 file: %w", err)
	}

	if err := tmpFile.Sync(); err != nil {
		_ = tmpFile.Close()
		return fmt.Errorf("sync L0 file: %w", err)
	}

	if err := tmpFile.Close(); err != nil {
		return fmt.Errorf("close L0 file: %w", err)
	}

	// Atomically rename temp file to final path

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check free disk space (df -h) and expand the volume if full.
  2. Remove stale *.tmp files in the L0 dir and fix their ownership (rm .../*.tmp; chown -R litestream ...).
  3. Verify the litestream process user has write permission on the L0 directory.
  4. Inspect the wrapped OS error for the exact path and errno.

Example fix

// before: stale tmp file owned by root blocks os.Create
$ ls -l /var/lib/db/ltx/0/*.tmp  # root:root
// after: clean and fix ownership
$ rm /var/lib/db/ltx/0/*.tmp && chown -R litestream:litestream /var/lib/db
Defensive patterns

Strategy: validation

Validate before calling

// Probe disk space and writability of the LTX dir
st, err := os.Statfs(l0Dir)
if err == nil && st.Bavail*uint64(st.Bsize) < 64*1024*1024 {
    log.Printf("low disk: %d bytes free", st.Bavail*uint64(st.Bsize))
}

Type guard

null

Try / catch

tmpFile, err := os.Create(tmpPath)
if err != nil {
    return fmt.Errorf("create temp L0 file: %w", err)
}
defer os.Remove(tmpPath) // clean stale tmp on failure

Prevention

When it happens

Trigger: checkDatabaseBehindReplica calls os.Create(tmpPath) after successfully opening the remote reader, and creation fails — L0 directory not writable, disk full, or a stale .tmp file with bad permissions exists from a previous crash.

Common situations: Disk-full on the volume holding the LTX directory; leftover .tmp file owned by root from an earlier run as a different user; read-only mount; tmpwatch/logrotate-like cleaners interfering in the LTX directory.

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/f14a04781a22c5ff. Report an issue: GitHub.