{"record":{"id":"ed5229e68b95d278","repo":"wavetermdev/waveterm","slug":"error-reading-request-body-v","errorCode":null,"errorMessage":"Error reading request body: %v","messagePattern":"Error reading request body: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"pkg/web/webvdomproto.go","lineNumber":47,"sourceCode":"\t// Simple UUID validation\n\tif len(uuid) != 36 {\n\t\thttp.Error(w, \"Invalid UUID format\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// Reconstruct the remaining path\n\tpath := \"/\" + strings.Join(pathParts[1:], \"/\")\n\tif r.URL.RawQuery != \"\" {\n\t\tpath += \"?\" + r.URL.RawQuery\n\t}\n\n\t// Read request body if present\n\tvar body []byte\n\tvar err error\n\tif r.Body != nil {\n\t\tbody, err = io.ReadAll(r.Body)\n\t\tif err != nil {\n\t\t\thttp.Error(w, fmt.Sprintf(\"Error reading request body: %v\", err), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tdefer r.Body.Close()\n\t}\n\n\t// Convert headers to map\n\theaders := make(map[string]string)\n\tfor key, values := range r.Header {\n\t\tif len(values) > 0 {\n\t\t\theaders[key] = values[0]\n\t\t}\n\t}\n\n\t// Prepare RPC request data\n\tdata := wshrpc.VDomUrlRequestData{\n\t\tMethod:  r.Method,\n\t\tURL:     path,\n\t\tHeaders: headers,","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/web/webvdomproto.go#L29-L65","documentation":"handleVDom reads the full request body with io.ReadAll; if that fails, pkg/web/webvdomproto.go:47 returns HTTP 500 with 'Error reading request body: <err>'. The underlying cause (connection reset, body size limit, timeout) is embedded in the message.","triggerScenarios":"The HTTP client disconnects mid-upload, a proxy/middleware truncates or aborts the body, or the server enforces a MaxBytesReader/timeout that trips while streaming the request body.","commonSituations":"Uploading large request payloads over flaky networks, load balancers with short idle timeouts killing long uploads, clients canceling requests (page navigation/AbortController) before the body finishes sending.","solutions":["Inspect the wrapped error in the response body to identify the root cause (unexpected EOF, context canceled, http: request body too large).","Retry the request from a stable connection; for aborted uploads this is usually transient.","Reduce request body size or raise server body limits (http.MaxBytesReader, proxy client_max_body_size).","Check proxy/load-balancer timeout settings so large or slow uploads are not terminated.","Ensure the client completes writing the body before awaiting the response."],"exampleFix":"// before: no limit handling, giant upload dies mid-stream\nresp := await fetch(\"/vdom/\"+id+\"/file\", {method: \"POST\", body: hugeBlob})\n\n// after: chunk or compress the payload\nconst compressed = gzipSync(hugeBlob)\nresp := await fetch(\"/vdom/\"+id+\"/file\", {method: \"POST\", body: compressed, headers: {\"Content-Encoding\": \"gzip\"}})","handlingStrategy":"retry","validationCode":"// check body size before upload\nif (body.length > MAX_BODY_BYTES) throw new Error(\"payload too large for /vdom endpoint\");","typeGuard":null,"tryCatchPattern":"const resp = await fetch(url, {method: \"POST\", body});\nif (resp.status === 500 && (await resp.text()).startsWith(\"Error reading request body\")) {\n  return retryWithBackoff(() => fetch(url, {method: \"POST\", body}));\n}","preventionTips":["Keep request bodies modest and compress large payloads.","Align client, proxy, and server timeouts so uploads are not cut off.","Avoid aborting requests while the body is still being sent."],"tags":["go","http","request-body","io"],"backgroundTag":"request-body-read-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}