{"record":{"id":"d7d675bce8452f95","repo":"OpenFeign/feign","slug":"s-reading-s-s","errorCode":null,"errorMessage":"%s reading %s %s","messagePattern":"(.+?) reading (.+?) (.+?)","errorType":"exception","errorClass":"FeignException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/feign/InvocationContext.java","lineNumber":127,"sourceCode":"    }\n\n    try {\n      final byte[] bodyData = Util.toByteArray(response.body().asInputStream());\n      return response.toBuilder().body(bodyData).build();\n    } finally {\n      ensureClosed(response.body());\n    }\n  }\n\n  private Object decode(Response response, Type returnType) {\n    try {\n      return decoder.decode(response, returnType);\n    } catch (final FeignException e) {\n      throw e;\n    } catch (final RuntimeException e) {\n      throw new DecodeException(response.status(), e.getMessage(), response.request(), e);\n    } catch (IOException e) {\n      throw errorReading(response.request(), response, e);\n    }\n  }\n\n  private Exception decodeError(String methodKey, Response response) {\n    try {\n      return errorDecoder.decode(methodKey, response);\n    } finally {\n      ensureClosed(response.body());\n    }\n  }\n\n  private boolean isVoidType(Type returnType) {\n    return returnType == Void.class\n        || returnType == void.class\n        || returnType.getTypeName().equals(\"kotlin.Unit\");\n  }\n\n  /**","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/OpenFeign/feign/blob/e2a1e27560a1e68840c34f031afca88b36096e30/core/src/main/java/feign/InvocationContext.java#L109-L145","documentation":"In InvocationContext.decode, when the configured Decoder throws a RuntimeException (not a FeignException), it is wrapped as a DecodeException whose message is \"%s reading %s %s\" (configKey, status, original message); IOExceptions are converted via errorReading. This means a response was received but decoding its body into the method's return type failed.","triggerScenarios":"Decoder throws while parsing the body: malformed JSON, JSON not matching the target type, wrong Content-Type/charset, empty body for a non-void type, or a decoder bug.","commonSituations":"Server returns HTML error page where JSON expected; missing or wrong decoder configured (e.g. no Jackson decoder registered); response schema changed upstream; stale generated DTOs after API version change.","solutions":["Inspect the wrapped cause (e.getMessage()) for the exact parse/mapping failure.","Register the correct decoder, e.g. Feign.builder().decoder(JacksonDecoder.create()) for JSON APIs.","Compare the actual response payload against the DTO fields/types and update the model.","Check the response Content-Type matches what the decoder expects."],"exampleFix":"// before\nFeign.builder().target(Api.class, url); // default decoder only handles String/byte[]\n// after\nFeign.builder()\n    .decoder(JacksonDecoder.create())\n    .target(Api.class, url);","handlingStrategy":"try-catch","validationCode":"// verify decoder matches the API media type before building the client\nif (!apiProducesJson) throw new IllegalStateException(\"register JSON decoder\");","typeGuard":null,"tryCatchPattern":"try {\n  return api.getData();\n} catch (DecodeException e) {\n  // log e.content() and cause to compare payload vs DTO; fall back or rethrow mapped error\n}","preventionTips":["Register the decoder matching your API (Jackson/Gson) via Feign.builder().decoder(...)","Keep DTOs in sync with the upstream response schema","Confirm response Content-Type matches the decoder","Capture the raw response body in logs at debug level for debugging decode failures"],"tags":["decode","serialization","response-body","decoder"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"e2a1e27560a1e68840c34f031afca88b36096e30","analyzedAt":"2026-09-10T12:37:37.238Z","contentChangedAt":"2026-09-10T12:37:37.238Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}