flowable/flowable-engine · error · FlowableException
Failed to read body
Error message
Failed to read body
What it means
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).
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.
Defensive patterns
Strategy: retry
Validate before calling
// no caller-side pre-check possible for server response malformation;
// validate response after the fact instead
if (response != null && response.getStatusCode() >= 200 && response.getStatusCode() < 300 && response.getBody() == null) {
log.warn("2xx response returned without a readable body");
} Try / catch
try {
return client.call(requestInfo);
} catch (FlowableException e) {
if ("Failed to read body".equals(e.getMessage()) && attempt < maxRetries) {
return retryWithBackoff(attempt + 1); // truncated responses are often transient
}
throw e;
} Prevention
- 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.
When it happens
Trigger: `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.
Common situations: Server closes the connection mid-body (truncated chunked transfer); malformed Content-Type headers (bad charset parameter) triggering ParseException; proxies cutting responses short.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- Cannot create multi part entity
- IO exception occurred
- IO exception occurred
- Activity needed for multi instance cannot bv found
- An error occurs creating a web-service client for WSDL '" +…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/1af991421ed0c526.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-http-common/src/main/java/org/flowable/http/common/impl/apache/client5/ApacheHttpComponents5FlowableHttpClient.java:360
headers.add(header.getName(), header.getValue());
}
responseInfo.setHttpHeaders(headers);
SimpleBody body = response.getBody();
if (body != null) {
if (body.isText()) {
responseInfo.setBody(body.getBodyText());
responseInfo.setBodyBytes(body.getBodyBytes());
} else {
try {
// We are creating a fake entity in order to rely on the creation of a String using the EntityUtils
// They contain some special logic for picking the default charset based on the content type
// (in case the content type doesn't have a charset)
responseInfo.setBody(EntityUtils.toString(new ByteArrayEntity(body.getBodyBytes(), body.getContentType())));
responseInfo.setBodyBytes(body.getBodyBytes());
} catch (IOException | ParseException e) {
throw new FlowableException("Failed to read body");
}
}
}
return responseInfo;
}
protected class ApacheHttpComponentsExecutableHttpRequest implements AsyncExecutableHttpRequest {
protected final AsyncRequestProducer request;
protected final RequestConfig requestConfig;
public ApacheHttpComponentsExecutableHttpRequest(AsyncRequestProducer request, RequestConfig requestConfig) {
this.request = request;
this.requestConfig = requestConfig;
}
View on GitHub (pinned to d6d39ce1c6)