benbjohnson/litestream · error

webdav: cannot create temp file: %w

Error message

webdav: cannot create temp file: %w

What it means

WriteLTXFile stages the incoming LTX stream to a temporary local file (to obtain a seekable reader with known size for Content-Length uploads). This error wraps the os.CreateTemp failure, meaning the local filesystem refused to create the temp file.

Source

Thrown at webdav/replica_client.go:259

	filename := litestream.LTXFilePath(c.Path, level, minTXID, maxTXID)

	var buf bytes.Buffer
	teeReader := io.TeeReader(rd, &buf)

	hdr, _, err := ltx.PeekHeader(teeReader)
	if err != nil {
		return nil, fmt.Errorf("extract timestamp from LTX header: %w", err)
	}
	timestamp := time.UnixMilli(hdr.Timestamp).UTC()

	// Stage to temporary file to get seekable reader with known size.
	// This ensures compatibility with all WebDAV servers and avoids the
	// unreliable chunked transfer encoding that causes silent data loss
	// on common configurations (Nginx+FastCGI, Lighttpd, Apache+FastCGI).
	tmpFile, err := os.CreateTemp("", "litestream-webdav-*.ltx")
	if err != nil {
		return nil, fmt.Errorf("webdav: cannot create temp file: %w", err)
	}
	defer func() {
		_ = tmpFile.Close()
		_ = os.Remove(tmpFile.Name())
	}()

	fullReader := io.MultiReader(&buf, rd)

	size, err := io.Copy(tmpFile, fullReader)
	if err != nil {
		return nil, fmt.Errorf("webdav: cannot copy to temp file: %w", err)
	}

	if _, err := tmpFile.Seek(0, io.SeekStart); err != nil {
		return nil, fmt.Errorf("webdav: cannot seek temp file: %w", err)
	}

	if err := client.MkdirAll(path.Dir(filename), 0755); err != nil {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check disk space on the partition holding the temp dir (df -h $TMPDIR)
  2. Verify TMPDIR is set to a writable directory, or unset it to use /tmp
  3. Fix permissions on the temp directory (writable by the litestream user)
  4. Mount a writable tmpfs/emptyDir at /tmp in the container

Example fix

// before
TMPDIR=/nonexistent litestream replicate ...  // fails
// after
mkdir -p /var/tmp/litestream && TMPDIR=/var/tmp/litestream litestream replicate ...
Defensive patterns

Strategy: validation

Validate before calling

tmpDir := os.TempDir()
if st, err := os.Stat(tmpDir); err != nil || !st.IsDir() { return fmt.Errorf("temp dir %s unavailable", tmpDir) }
probe, err := os.CreateTemp(tmpDir, "probe-*"); if err != nil { return err }; probe.Close(); os.Remove(probe.Name())

Try / catch

if err := runReplication(ctx); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.ENOSPC) { /* free disk or relocate TMPDIR */ }
}

Prevention

When it happens

Trigger: os.CreateTemp("", "litestream-webdav-*.ltx") fails: TMPDIR points to a nonexistent/unwritable directory, or the disk holding os.TempDir() is full.

Common situations: Containers with read-only /tmp, TMPDIR misconfigured in systemd units or Docker, full disk on the litestream host.

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