benbjohnson/litestream · error

webdav: cannot seek temp file: %w

Error message

webdav: cannot seek temp file: %w

What it means

Before uploading, the staged temp file must be rewound to the start so its full contents can be sent. This error wraps a tmpFile.Seek failure, which is nearly always an OS-level I/O problem rather than a logical one.

Source

Thrown at webdav/replica_client.go:274

	// 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 {
		return nil, fmt.Errorf("webdav: cannot create parent directory %q: %w", path.Dir(filename), err)
	}

	// Upload with Content-Length header using seekable temp file.
	// WriteStreamWithLength requires both a seekable reader and known size,
	// which we now have from the temp file. This avoids chunked encoding
	// and ensures reliable uploads across all WebDAV server configurations.
	if err := client.WriteStreamWithLength(filename, tmpFile, size, 0644); err != nil {
		return nil, fmt.Errorf("webdav: cannot write file %q: %w", filename, err)
	}

	internal.OperationTotalCounterVec.WithLabelValues(ReplicaClientType, "PUT").Inc()
	internal.OperationBytesCounterVec.WithLabelValues(ReplicaClientType, "PUT").Add(float64(size))

	return &ltx.FileInfo{

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Check dmesg/system logs for disk I/O errors on the temp filesystem
  2. Verify the temp directory is on a local filesystem (avoid FUSE/network mounts for TMPDIR)
  3. Retry the operation; transient I/O errors may clear
  4. Check file descriptor limits if many concurrent writes are running
Defensive patterns

Strategy: retry

Validate before calling

probe, err := os.CreateTemp(os.TempDir(), "seek-probe-*")
if err == nil { _, serr := probe.Seek(0, io.SeekStart); probe.Close(); os.Remove(probe.Name()); _ = serr }

Try / catch

err := replicate(ctx)
if err != nil && errors.Is(err, syscall.EIO) { /* check hardware/fs health, then retry */ }

Prevention

When it happens

Trigger: os.File.Seek on the just-written temp file fails, typically due to underlying filesystem errors (rare; e.g. I/O errors on the device, or the file descriptor became invalid).

Common situations: Failing disk/hardware I/O errors, exotic filesystems (some network mounts) with unreliable seek behavior, fd exhaustion side effects.

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