{"record":{"id":"62778a87ebad7455","repo":"benbjohnson/litestream","slug":"webdav-cannot-write-file-q-w","errorCode":null,"errorMessage":"webdav: cannot write file %q: %w","messagePattern":"webdav: cannot write file %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"webdav/replica_client.go","lineNumber":286,"sourceCode":"\tsize, err := io.Copy(tmpFile, fullReader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"webdav: cannot copy to temp file: %w\", err)\n\t}\n\n\tif _, err := tmpFile.Seek(0, io.SeekStart); err != nil {\n\t\treturn nil, fmt.Errorf(\"webdav: cannot seek temp file: %w\", err)\n\t}\n\n\tif err := client.MkdirAll(path.Dir(filename), 0755); err != nil {\n\t\treturn nil, fmt.Errorf(\"webdav: cannot create parent directory %q: %w\", path.Dir(filename), err)\n\t}\n\n\t// Upload with Content-Length header using seekable temp file.\n\t// WriteStreamWithLength requires both a seekable reader and known size,\n\t// which we now have from the temp file. This avoids chunked encoding\n\t// and ensures reliable uploads across all WebDAV server configurations.\n\tif err := client.WriteStreamWithLength(filename, tmpFile, size, 0644); err != nil {\n\t\treturn nil, fmt.Errorf(\"webdav: cannot write file %q: %w\", filename, err)\n\t}\n\n\tinternal.OperationTotalCounterVec.WithLabelValues(ReplicaClientType, \"PUT\").Inc()\n\tinternal.OperationBytesCounterVec.WithLabelValues(ReplicaClientType, \"PUT\").Add(float64(size))\n\n\treturn &ltx.FileInfo{\n\t\tLevel:     level,\n\t\tMinTXID:   minTXID,\n\t\tMaxTXID:   maxTXID,\n\t\tSize:      size,\n\t\tCreatedAt: timestamp,\n\t}, nil\n}\n\nfunc (c *ReplicaClient) OpenLTXFile(ctx context.Context, level int, minTXID, maxTXID ltx.TXID, offset, size int64) (_ io.ReadCloser, err error) {\n\tclient, err := c.init(ctx)\n\tif err != nil {\n\t\treturn nil, err","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/webdav/replica_client.go#L268-L304","documentation":"The final upload step calls client.WriteStreamWithLength to PUT the temp file to the WebDAV server with an explicit Content-Length. This error wraps any HTTP-level upload failure: rejected credentials, quota exceeded, connection drop, or server-side error responses.","triggerScenarios":"PUT request to the WebDAV server fails: 401/403 auth failure, 507 insufficient storage quota, connection reset/timeout mid-upload, or server rejecting large bodies.","commonSituations":"Expired or wrong WebDAV credentials in config, storage quota full on the WebDAV account, reverse proxies (Nginx) with client_max_body_size limits, unstable connections dropping long uploads.","solutions":["Check credentials and quota on the WebDAV server account","Raise proxy body-size limits (e.g. nginx client_max_body_size) and timeouts","Inspect the wrapped underlying gowebdav error for the exact HTTP status","Test the upload path manually with curl -T file to isolate network vs auth issues"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// precheck: credentials and quota\nclient, _ := gowebdav.NewClient(serverURL, user, pass)\nif err := client.Connect(); err != nil { return err }\nprobe, _ := os.CreateTemp(\"\", \"probe\"); probe.WriteString(\"x\")\nerr := client.Write(path.Join(basePath, \".probe\"), probe)\nprobe.Close(); os.Remove(probe.Name())\nif err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err := writeLTX(ctx); err != nil {\n    if errors.Is(err, context.DeadlineExceeded) || isConnReset(err) { retry with exponential backoff }\n    // 401/403/507 are not retryable: fix credentials/quota first\n}","preventionTips":["Rotate WebDAV credentials before expiry","Monitor quota usage on the WebDAV account","Raise proxy client_max_body_size and timeouts for large LTX files","Use stable network paths for long uploads"],"tags":["webdav","upload","http"],"backgroundTag":"http-error-response","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}