{"record":{"id":"1af991421ed0c526","repo":"flowable/flowable-engine","slug":"failed-to-read-body","errorCode":null,"errorMessage":"Failed to read body","messagePattern":"Failed to read body","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-http-common/src/main/java/org/flowable/http/common/impl/apache/client5/ApacheHttpComponents5FlowableHttpClient.java","lineNumber":360,"sourceCode":"            headers.add(header.getName(), header.getValue());\n        }\n\n        responseInfo.setHttpHeaders(headers);\n\n        SimpleBody body = response.getBody();\n        if (body != null) {\n            if (body.isText()) {\n                responseInfo.setBody(body.getBodyText());\n                responseInfo.setBodyBytes(body.getBodyBytes());\n            } else {\n                try {\n                    // We are creating a fake entity in order to rely on the creation of a String using the EntityUtils\n                    // They contain some special logic for picking the default charset based on the content type\n                    // (in case the content type doesn't have a charset)\n                    responseInfo.setBody(EntityUtils.toString(new ByteArrayEntity(body.getBodyBytes(), body.getContentType())));\n                    responseInfo.setBodyBytes(body.getBodyBytes());\n                } catch (IOException | ParseException e) {\n                    throw new FlowableException(\"Failed to read body\");\n                }\n            }\n        }\n\n        return responseInfo;\n\n    }\n\n    protected class ApacheHttpComponentsExecutableHttpRequest implements AsyncExecutableHttpRequest {\n\n        protected final AsyncRequestProducer request;\n        protected final RequestConfig requestConfig;\n\n        public ApacheHttpComponentsExecutableHttpRequest(AsyncRequestProducer request, RequestConfig requestConfig) {\n            this.request = request;\n            this.requestConfig = requestConfig;\n        }\n","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-http-common/src/main/java/org/flowable/http/common/impl/apache/client5/ApacheHttpComponents5FlowableHttpClient.java#L342-L378","documentation":"When converting the Apache HttpClient 5 response into Flowable's `FlowableHttpResponseInfo`, the client re-reads a buffered body via `EntityUtils.toString(...)` to produce the String body while keeping the raw bytes. If that conversion throws `IOException` or `ParseException`, `toFlowableHttpResponse` throws this `FlowableException` (note: the original exception is not chained).","triggerScenarios":"`toFlowableHttpResponse()` encounters an `IOException` or `ParseException` while calling `EntityUtils.toString` on the response body — e.g. a truncated/chunk-decoding error or a Content-Type header `EntityUtils` cannot parse.","commonSituations":"Server closes the connection mid-body (truncated chunked transfer); malformed Content-Type headers (bad charset parameter) triggering ParseException; proxies cutting responses short.","solutions":["Check server/proxy logs for truncated responses; a mid-body disconnect is the most common cause.","Fix the response's Content-Type header on the server side — an invalid charset parameter makes EntityUtils throw ParseException.","Retry the request if the failure is a transient network truncation.","If the exception lacks a cause, add server-side response validation/capture (or a proxy like tcpdump/Wireshark) to see the raw malformed response."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// no caller-side pre-check possible for server response malformation;\n// validate response after the fact instead\nif (response != null && response.getStatusCode() >= 200 && response.getStatusCode() < 300 && response.getBody() == null) {\n    log.warn(\"2xx response returned without a readable body\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return client.call(requestInfo);\n} catch (FlowableException e) {\n    if (\"Failed to read body\".equals(e.getMessage()) && attempt < maxRetries) {\n        return retryWithBackoff(attempt + 1); // truncated responses are often transient\n    }\n    throw e;\n}","preventionTips":["Ensure the server sends a valid Content-Type with a proper charset parameter.","Investigate proxies/LBs that truncate long responses.","Set sane response size/timeouts on the client.","Remember this FlowableException has no cause — capture raw traffic if it persists."],"tags":["response-body","io","http-client","parsing"],"backgroundTag":"invalid-json-response","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}