{"record":{"id":"c6a54bcdfccdccf3","repo":"lysine-dev/retrofit","slug":"json-document-was-not-fully-consumed","errorCode":null,"errorMessage":"JSON document was not fully consumed.","messagePattern":"JSON document was not fully consumed\\.","errorType":"exception","errorClass":"JsonIOException","httpStatus":null,"severity":"error","filePath":"retrofit-converters/gson/src/main/java/retrofit2/converter/gson/GsonResponseBodyConverter.java","lineNumber":42,"sourceCode":"import okhttp3.ResponseBody;\nimport retrofit2.Converter;\n\nfinal class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {\n  private final Gson gson;\n  private final TypeAdapter<T> adapter;\n\n  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {\n    this.gson = gson;\n    this.adapter = adapter;\n  }\n\n  @Override\n  public T convert(ResponseBody value) throws IOException {\n    JsonReader jsonReader = gson.newJsonReader(value.charStream());\n    try {\n      T result = adapter.read(jsonReader);\n      if (jsonReader.peek() != JsonToken.END_DOCUMENT) {\n        throw new JsonIOException(\"JSON document was not fully consumed.\");\n      }\n      return result;\n    } finally {\n      value.close();\n    }\n  }\n}\n","sourceCodeStart":24,"sourceCodeEnd":50,"githubUrl":"https://github.com/lysine-dev/retrofit/blob/d0b112dad073b7fe49c953ebc46ff1b424cb1e51/retrofit-converters/gson/src/main/java/retrofit2/converter/gson/GsonResponseBodyConverter.java#L24-L50","documentation":"Thrown by GsonResponseBodyConverter.convert() as a JsonIOException after the registered TypeAdapter finishes reading. The converter reads one JSON value from the response body, then peeks the JsonReader; if the next token is not END_DOCUMENT (i.e. there is trailing content after the top-level value), it refuses to return a partial/ambiguous result and throws. This guards against silently ignoring malformed or concatenated JSON payloads.","triggerScenarios":"An HTTP response body that contains extra data after the single expected JSON value: multiple concatenated JSON objects, a JSON value followed by trailing characters/whitespace-with-content, a server streaming multiple documents into one body, or a proxy that appended diagnostics after the JSON.","commonSituations":"A backend that emits `{...}{...}` (two objects) in a single response, a misconfigured CDN/edge proxy appending analytics or error HTML, a debug-mode server echoing the request body after the response JSON, or a partial read by a custom TypeAdapter that consumed only part of the value.","solutions":["Inspect the raw response body (e.g. via an OkHttp logging interceptor at BODY level) to identify the trailing content and fix the server/proxy emitting it.","If concatenated documents are intentional, switch to a streaming reader that loops on peek()!=END_DOCUMENT instead of using GsonResponseBodyConverter.","If a custom TypeAdapter is leaving the reader mid-value, fix the adapter to fully consume its token range.","Disable any server debug/echo flags or proxy body-rewriting that appends content after the JSON payload."],"exampleFix":"// before — server returns: {\"id\":1}{\"id\":2}\n// converter throws after reading the first object.\n\n// after — fix the endpoint to return a single JSON value or array:\n[{\"id\":1},{\"id\":2}]","handlingStrategy":"try-catch","validationCode":"// Validate the body shape before handing it to Retrofit/Gson when the source is suspect.\n// This is only for non-Retrofit call paths; Retrofit owns ResponseBody reading internally.\nString body = response.body().string();\nJsonReader reader = new JsonReader(new StringReader(body));\nnew Gson().getAdapter(SomeType.class).read(reader);\nif (reader.peek() != JsonToken.END_DOCUMENT) {\n  log.warn(\"Trailing JSON content detected; investigate the server response.\");\n}","typeGuard":null,"tryCatchPattern":"// Wrap the converter call (typically inside a custom Converter or interceptor) and surface a\n// parse error with context rather than letting JsonIOException escape raw.\ntry {\n  return converter.convert(response.body());\n} catch (JsonIOException e) {\n  if (\"JSON document was not fully consumed.\".equals(e.getMessage())) {\n    throw new IllegalStateException(\"Server returned trailing JSON content; see raw body logs\", e);\n  }\n  throw e;\n}","preventionTips":["Enable an OkHttp logging interceptor at BODY level in non-prod builds to see raw responses.","Investigate any server endpoint that returns concatenated JSON objects or appended diagnostics.","Ensure custom TypeAdapters consume their full token range, not a prefix."],"tags":["retrofit","gson","json","response-parsing"],"backgroundTag":null,"analyzedSha":"d0b112dad073b7fe49c953ebc46ff1b424cb1e51","analyzedAt":"2026-08-13T23:49:47.955Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}