OpenFeign/feign · error · FeignException

reading (response body)

Error message

%s reading %s %s (response body)

What it means

In InvocationContext.proceed, when the response status should NOT have its body decoded (status outside 2xx, or 404 without dismiss404 on a non-void type), decodeError is invoked to produce the exception from the ErrorDecoder, whose message is formatted "%s reading %s %s (response body)". It signals the library refused to decode a body because the response was not a decodable success (or dismissible 404).

Solutions

  1. Read the FeignException's status and content from the ErrorDecoder to see the server's error payload.
  2. Install a custom ErrorDecoder to map expected statuses to domain exceptions or defaults.
  3. Enable dismiss404 (404 -> null) via options if 404 is an acceptable outcome for non-void methods.
  4. Fix the client-side cause (bad id, wrong URL, expired credentials) indicated by the status code.

Example fix

// before
Feign.builder().target(UserApi.class, url);
// after
Feign.builder()
    .dismiss404()
    .errorDecoder(new ErrorDecoder() {
      public Exception decode(String methodKey, Response response) {
        if (response.status() == 404) return new UserNotFoundException(methodKey);
        return new Default().decode(methodKey, response);
      }
    })
    .target(UserApi.class, url);
Defensive patterns

Strategy: try-catch

Try / catch

try {
  return api.getUser(id);
} catch (FeignException e) {
  switch (e.status()) {
    case 404: return Optional.empty();
    case 429: throw new RateLimitedException(e);
    default: throw e;
  }
}

Prevention

When it happens

Trigger: Server returned 4xx/5xx (non-2xx) for a method call; server returned 404 while dismiss404 is false (or the method's return type is not void); a redirect/status the ErrorDecoder maps to an exception.

Common situations: Upstream API returning 500 during an outage; resource genuinely missing (404) on a typed endpoint; wrong base URL hitting an error page; rate limiting 429 responses.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10). Data as JSON: /api/errors/eb2c035a9c50dfa9. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/feign/InvocationContext.java:80

    return returnType;
  }

  public Response response() {
    return response;
  }

  public Object proceed() throws Exception {
    if (returnType == Response.class) {
      return disconnectResponseBodyIfNeeded(response);
    }

    try {
      final boolean shouldDecodeResponseBody =
          (response.status() >= 200 && response.status() < 300)
              || (response.status() == 404 && dismiss404 && !isVoidType(returnType));

      if (!shouldDecodeResponseBody) {
        throw decodeError(configKey, response);
      }

      if (isVoidType(returnType) && !decodeVoid) {
        ensureClosed(response.body());
        return kotlinUnitInstance(returnType);
      }

      Class<?> rawType = Types.getRawType(returnType);
      if (TypedResponse.class.isAssignableFrom(rawType)) {
        Type bodyType = Types.resolveLastTypeParameter(returnType, TypedResponse.class);
        return TypedResponse.builder(response).body(decode(response, bodyType)).build();
      }

      return decode(response, returnType);
    } finally {
      if (closeAfterDecode) {
        ensureClosed(response.body());
      }

View on GitHub (pinned to e2a1e27560)