{"id":"2a70302d64d6c465","repo":"google/gson","slug":"jsonreader-is-closed","errorCode":null,"errorMessage":"JsonReader is closed","messagePattern":"JsonReader is closed","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java","lineNumber":166,"sourceCode":"    } else if (o instanceof JsonObject) {\n      return JsonToken.BEGIN_OBJECT;\n    } else if (o instanceof JsonArray) {\n      return JsonToken.BEGIN_ARRAY;\n    } else if (o instanceof JsonPrimitive) {\n      JsonPrimitive primitive = (JsonPrimitive) o;\n      if (primitive.isString()) {\n        return JsonToken.STRING;\n      } else if (primitive.isBoolean()) {\n        return JsonToken.BOOLEAN;\n      } else if (primitive.isNumber()) {\n        return JsonToken.NUMBER;\n      } else {\n        throw new AssertionError();\n      }\n    } else if (o instanceof JsonNull) {\n      return JsonToken.NULL;\n    } else if (o == SENTINEL_CLOSED) {\n      throw new IllegalStateException(\"JsonReader is closed\");\n    } else {\n      throw new MalformedJsonException(\n          \"Custom JsonElement subclass \" + o.getClass().getName() + \" is not supported\");\n    }\n  }\n\n  private Object peekStack() {\n    return stack[stackSize - 1];\n  }\n\n  @CanIgnoreReturnValue\n  private Object popStack() {\n    Object result = stack[--stackSize];\n    stack[stackSize] = null;\n    return result;\n  }\n\n  private void expect(JsonToken expected) throws IOException {","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java#L148-L184","documentation":"JsonTreeReader.peek throws IllegalStateException('JsonReader is closed') when the only item on the stack is the SENTINEL_CLOSED marker, i.e. close() was previously called on this JsonTreeReader. After close(), the reader replaces its stack with the sentinel and any further peek/next/hasNext call hits this guard.","triggerScenarios":"Calling any read operation on a JsonTreeReader (constructed from a JsonElement) after invoking close() on it. Common in try-with-resources blocks where the JsonReader is auto-closed but reused afterwards.","commonSituations":"Wrapping JsonParser.parseReader in try-with-resources and then trying to use the reader; utility methods that close a JsonReader and the caller re-uses it; thread-handoff where one side closes and another reads.","solutions":["Do not use a JsonReader after calling close(); create a fresh JsonReader for each parse.","Do not put JsonReader in try-with-resources if you intend to inspect it afterwards — close only when fully done.","Audit custom TypeAdapters that accept a JsonReader to ensure they don't close it (Gson owns the lifecycle).","If a reader must be reused, re-create it from the original JsonElement/string each time."],"exampleFix":"// before\nJsonReader r = new JsonTreeReader(jsonElement);\nr.close();\nr.peek(); // IllegalStateException: JsonReader is closed\n\n// after\nJsonReader r = new JsonTreeReader(jsonElement);\nJsonElement e = JsonParser.parseReader(r); // use, then discard\nr = new JsonTreeReader(jsonElement); // recreate if needed","handlingStrategy":"validation","validationCode":"// Track open/closed state of readers you hand out\nAtomicBoolean open = new AtomicBoolean(true);\nJsonReader r = new JsonTreeReader(element);\n// later, before use:\nif (!open.get()) throw new IllegalStateException(\"Reader already closed\");\nr.peek();","typeGuard":null,"tryCatchPattern":"try {\n  reader.peek();\n} catch (IllegalStateException e) {\n  if (\"JsonReader is closed\".equals(e.getMessage())) {\n    // recreate the reader or surface a clear error\n    reader = new JsonTreeReader(originalElement);\n  } else throw e;\n}","preventionTips":["Treat JsonReader as single-use; create a new one per parse.","Do not put JsonReader in try-with-resources unless you discard it immediately after.","Document ownership in helper methods that accept a JsonReader."],"tags":["jsonreader","lifecycle","io","json-tree"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}