{"id":"bd0fa4c2110ecb76","repo":"google/gson","slug":"incomplete-document","errorCode":null,"errorMessage":"Incomplete document","messagePattern":"Incomplete document","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/JsonTreeWriter.java","lineNumber":250,"sourceCode":"  @CanIgnoreReturnValue\n  @Override\n  public JsonWriter nullValue() throws IOException {\n    put(JsonNull.INSTANCE);\n    return this;\n  }\n\n  @Override\n  public JsonWriter jsonValue(String value) throws IOException {\n    throw new UnsupportedOperationException();\n  }\n\n  @Override\n  public void flush() throws IOException {}\n\n  @Override\n  public void close() throws IOException {\n    if (!stack.isEmpty()) {\n      throw new IOException(\"Incomplete document\");\n    }\n    stack.add(SENTINEL_CLOSED);\n  }\n}\n","sourceCodeStart":232,"sourceCodeEnd":255,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/JsonTreeWriter.java#L232-L255","documentation":"Thrown by JsonTreeWriter.close() as an IOException when the stack is non-empty at close time, meaning there are unclosed JSON arrays or objects. close() requires a complete (balanced) document; leftover open containers make the document incomplete. After a successful close, a SENTINEL_CLOSED marker is pushed so further operations fail fast.","triggerScenarios":"Calling close() on a JsonTreeWriter that has had beginObject()/beginArray() without matching end calls. Common when a TypeAdapter uses try-with-resources on the writer (which calls close()) but its write path threw before closing all containers.","commonSituations":"A serializer wrapped in try-with-resources where an inner exception skips endObject()/endArray(); manual use of JsonTreeWriter that forgets to balance; adapters that early-return without closing nested structures; integration code that always closes the writer defensively.","solutions":["Ensure every beginObject()/beginArray() is matched by endObject()/endArray() before close(); use try/finally to close containers even on exceptions, separate from the writer close().","Don't rely on close() to fix up open containers; it intentionally throws to surface the bug.","Track nesting depth and assert it is zero before close() in development builds.","Restructure serializers so the close of containers happens in the same scope as the open."],"exampleFix":"// before: try-with-resources closes while object still open\ntry (JsonTreeWriter w = new JsonTreeWriter()) {\n  w.beginObject().name(\"a\").value(1);\n  // forgot endObject(); w.close() throws IOException: Incomplete document\n}\n\n// after: close containers before writer.close()\nJsonTreeWriter w = new JsonTreeWriter();\nw.beginObject();\ntry {\n  w.name(\"a\").value(1);\n} finally {\n  w.endObject();\n}\nw.close();","handlingStrategy":"validation","validationCode":"// Close all containers before closing the writer\nw.endObject(); // (and any nested end calls)\n// only then:\nw.close();","typeGuard":null,"tryCatchPattern":"try {\n  w.close();\n} catch (IOException e) {\n  if (\"Incomplete document\".equals(e.getMessage())) {\n    // unclosed containers: log and discard, or attempt to balance\n    throw new IOException(\"Cannot close: unclosed JSON containers remain\", e);\n  }\n  throw e;\n}","preventionTips":["Use try/finally to close containers before writer.close(); don't rely on close() to clean up.","Track nesting depth and assert zero before close() in dev builds.","Keep container open and close in the same lexical scope."],"tags":["json","streaming","writer-state","gson","resource-management","io"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}