OpenFeign/feign · error · FeignException
reading
Error message
%s reading %s %s
What it means
In ResponseHandler.handleResponse, an IOException raised while reading/decoding the response is logged (if logLevel != NONE) and rethrown as a FeignException built by errorReading with message "%s reading %s %s". Any other exception triggers ensureClosed(response.body()) and propagates. It indicates the response arrived but its body could not be read or processed.
Solutions
- Check the wrapped IOException cause: premature EOF points to connection/proxy issues, timeout points to slow body transfer.
- Increase read timeout in Request.Options for large payloads.
- Verify proxy/LB idle timeouts are larger than the expected body transfer time.
- Ensure the response body is read exactly once and Content-Encoding headers match the actual payload.
Example fix
// before new Request.Options(2000, 2000); // after new Request.Options(5, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
Defensive patterns
Strategy: retry
Try / catch
try {
return api.download();
} catch (FeignException e) {
if (e.getCause() instanceof IOException io && isTransient(io)) {
return retryWithBackoff(() -> api.download());
}
throw e;
} Prevention
- Size read timeouts to the largest expected response body
- Check LB/proxy idle timeouts exceed transfer duration
- Only read the response body once per response
- Verify Content-Encoding (gzip) is handled by the client configuration
When it happens
Trigger: Connection closed mid-body read (truncated response); body stream IO failure while the decoder consumes it; decompression failure on gzip-encoded bodies; reading a body after the connection was already released.
Common situations: Load balancer or proxy terminating the connection early; very large responses hitting socket timeouts mid-read; misconfigured gzip; calling response.body() again after a prior read.
Related errors
AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10).
Data as JSON: /api/errors/9cc275e96c1ee728.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/feign/ResponseHandler.java:83
public Object handleResponse(
String configKey, Response response, Type returnType, long elapsedTime) throws Exception {
try {
response = logAndRebufferResponseIfNeeded(configKey, response, elapsedTime);
return executionChain.next(
new InvocationContext(
configKey,
decoder,
errorDecoder,
dismiss404,
closeAfterDecode,
decodeVoid,
response,
returnType));
} catch (final IOException e) {
if (logLevel != Level.NONE) {
logger.logIOException(configKey, logLevel, e, elapsedTime);
}
throw errorReading(response.request(), response, e);
} catch (Exception e) {
ensureClosed(response.body());
throw e;
}
}
private Response logAndRebufferResponseIfNeeded(
String configKey, Response response, long elapsedTime) throws IOException {
if (logLevel == Level.NONE) {
return response;
}
return logger.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
}
}
View on GitHub (pinned to e2a1e27560)