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 <x.FileInfo{View on GitHub (pinned to 4ed7a308f6)
Solutions
- Check dmesg/system logs for disk I/O errors on the temp filesystem
- Verify the temp directory is on a local filesystem (avoid FUSE/network mounts for TMPDIR)
- Retry the operation; transient I/O errors may clear
- 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
- Keep TMPDIR on local filesystems, not FUSE/network mounts
- Watch dmesg for disk I/O errors
- Avoid fd leaks that can corrupt descriptor state
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
- failed to scan directory %s: %w
- cannot remove tmp files: %w
- close L0 file: %w
- write page %d: %w
- sync before truncate: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/fb0ee415d7436d98.
Report an issue: GitHub.