{"record":{"id":"f887d0c9c0bef8fb","repo":"plandex-ai/plandex","slug":"error-reading-request-body-f887d0","errorCode":null,"errorMessage":"Error reading request body","messagePattern":"Error reading request body","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/plans_changes.go","lineNumber":130,"sourceCode":"\t}\n\n\tvars := mux.Vars(r)\n\tplanId := vars[\"planId\"]\n\tbranch := vars[\"branch\"]\n\tlog.Println(\"planId: \", planId, \"branch: \", branch)\n\n\tplan := authorizePlan(w, planId, auth)\n\tif plan == nil {\n\t\treturn\n\t}\n\n\tvar err error\n\n\t// read the request body\n\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\tlog.Printf(\"Error reading request body: %v\\n\", err)\n\t\thttp.Error(w, \"Error reading request body\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\tdefer r.Body.Close()\n\n\tvar requestBody shared.ApplyPlanRequest\n\tif err := json.Unmarshal(body, &requestBody); err != nil {\n\t\tlog.Printf(\"Error parsing request body: %v\\n\", err)\n\t\thttp.Error(w, \"Error parsing request body\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// Just in case this was sent immediately after a stream finished, wait a little before locking to allow for cleanup\n\ttime.Sleep(100 * time.Millisecond)\n\n\tctx, cancel := context.WithCancel(r.Context())\n\n\tvar settings *shared.PlanSettings\n\tvar currentPlanParams db.CurrentPlanStateParams","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_changes.go#L112-L148","documentation":"ApplyPlanHandler could not read the raw request body via io.ReadAll(r.Body) and returns 500 'Error reading request body'. Unlike JSON parsing errors (which are 400), this means the byte stream itself failed — the connection broke or the body could not be delivered.","triggerScenarios":"Client disconnects mid-upload; proxy/load balancer terminates the connection; request exceeds a body size limit and the server/transport resets the stream.","commonSituations":"Unstable network or VPN dropping large uploads; reverse proxy (nginx) closing the request due to client_max_body_size; client timeout set shorter than upload time.","solutions":["Check client-side network stability and retry the apply","Raise the reverse proxy body size limit (e.g. nginx client_max_body_size) if bodies are large","Increase client HTTP timeout so the body finishes streaming","Confirm no intermediary (LB, service mesh) is resetting the connection"],"exampleFix":"null","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  const res = await fetch(applyUrl, {body: raw, signal: AbortSignal.timeout(60000)});\n  if (res.status === 500 && (await res.text()).includes('Error reading request body')) {\n    // connection dropped mid-upload — retry with backoff\n  }\n} catch (e) { /* network error path */ }","preventionTips":["Use generous HTTP timeouts for apply requests","Check reverse proxy body-size and timeout limits (e.g. nginx client_max_body_size)","Retry idempotently-safe reads before apply on network errors","Avoid applying over unstable connections/VPNs with large bodies"],"tags":["http","network","request-body","io"],"backgroundTag":"request-body-read-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}