{"record":{"id":"c5edfa4048215619","repo":"crowdsecurity/crowdsec","slug":"unable-to-read-body-w","errorCode":null,"errorMessage":"unable to read body: %w","messagePattern":"unable to read body: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/appsec/request.go","lineNumber":335,"sourceCode":"\tif maxSize <= 0 {\n\t\tmaxSize = DefaultMaxBodySize\n\t}\n\n\taction := bodySettings.Action\n\tif action == \"\" {\n\t\taction = BodySizeActionDrop\n\t}\n\n\t// Always read from the actual stream — never trust Content-Length.\n\t// Read up to maxSize+1 bytes so we can detect whether the body exceeds the limit.\n\tbody, err = io.ReadAll(io.LimitReader(r.Body, maxSize+1))\n\tvar netErr net.Error\n\thasTimedout := err != nil && errors.As(err, &netErr) && netErr.Timeout()\n\t// ErrUnexpectedEOF can occur on POST requests without a body — accept what was read.\n\t// A net.Error timeout means the read deadline fired; keep what we got and move on.\n\t// Bouncers are semi-trusted; misbehaving ones would otherwise stall the WAF for seconds.\n\tif err != nil && !errors.Is(err, io.ErrUnexpectedEOF) && !hasTimedout {\n\t\treturn nil, false, false, fmt.Errorf(\"unable to read body: %w\", err)\n\t}\n\n\tif int64(len(body)) > maxSize {\n\t\t// Drain remaining bytes so the client doesn't time out waiting for us to finish reading.\n\t\t// The LimitReader stopped at maxSize+1, so r.Body may still have unread bytes.\n\t\t_, _ = io.Copy(io.Discard, r.Body)\n\n\t\tswitch action {\n\t\tcase BodySizeActionDrop:\n\t\t\tlogger.Warnf(\"request body exceeds limit %d bytes, will drop request\", maxSize)\n\t\t\tbody = nil\n\t\t\texceeded = true\n\t\tcase BodySizeActionAllow:\n\t\t\tlogger.Warnf(\"request body exceeds limit %d bytes, skipping body inspection\", maxSize)\n\t\t\tbody = nil\n\t\tcase BodySizeActionPartial:\n\t\t\tlogger.Warnf(\"request body exceeds limit %d bytes, truncating\", maxSize)\n\t\t\tbody = body[:maxSize]","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/appsec/request.go#L317-L353","documentation":"readRequestBody reads the bouncer-forwarded body with a size-limited reader and tolerates ErrUnexpectedEOF and read-timeout errors (partial bodies on empty POSTs / deadline expiry are accepted). This error is returned for any other body-read failure, meaning the connection errored in a way the WAF cannot safely continue from.","triggerScenarios":"NewParsedRequestFromRequest → readRequestBody when r.Body read fails with an error that is neither io.ErrUnexpectedEOF nor a net.Error timeout — e.g. connection reset by the bouncer mid-body, TLS errors, or aborted connections.","commonSituations":"Bouncer or reverse proxy closing the connection while the body is still being read, client aborts, keep-alive races, or network interruptions between bouncer and crowdsec. Usually a symptom of upstream flakiness rather than a crowdsec bug.","solutions":["Check connectivity and timeouts between the bouncer/proxy and crowdsec appsec component","Look at bouncer logs for aborted requests or mismatches in Content-Length","Increase bouncer-side timeouts if large bodies are regularly cut off","If persistent on one path, capture traffic to identify who resets the connection"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"null","typeGuard":null,"tryCatchPattern":"pr, _, _, err := NewParsedRequestFromRequest(r, logger)\nif err != nil {\n    log.Debugf(\"unreadable request body: %v\", err)\n    http.Error(w, \"bad request\", http.StatusBadRequest)\n    return\n}","preventionTips":["Keep bouncer timeouts generous enough for the largest expected bodies","Monitor connection resets between bouncer and appsec","Upgrade bouncers to keep body-forwarding behavior in sync"],"tags":["network","io","body","appsec"],"backgroundTag":"request-body-read-failed","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}