{"record":{"id":"a4c3bfefa4daffe1","repo":"apache/hadoop","slug":"expecting-edits","errorCode":null,"errorMessage":"expecting </EDITS>","messagePattern":"expecting </EDITS>","errorType":"validation","errorClass":"InvalidXmlException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineEditsViewer/OfflineEditsXmlLoader.java","lineNumber":128,"sourceCode":"    } finally {\n      fileReader.close();\n    }\n  }\n  \n  @Override\n  public void startDocument() {\n    state = ParseState.EXPECT_EDITS_TAG;\n    stanza = null;\n    stanzaStack = new Stack<Stanza>();\n    opCode = null;\n    cbuf = new StringBuilder();\n    nextTxId = -1;\n  }\n  \n  @Override\n  public void endDocument() {\n    if (state != ParseState.EXPECT_END) {\n      throw new InvalidXmlException(\"expecting </EDITS>\");\n    }\n  }\n  \n  @Override\n  public void startElement (String uri, String name,\n      String qName, Attributes atts) {\n    switch (state) {\n    case EXPECT_EDITS_TAG:\n      if (!name.equals(\"EDITS\")) {\n        throw new InvalidXmlException(\"you must put \" +\n            \"<EDITS> at the top of the XML file! \" +\n            \"Got tag \" + name + \" instead\");\n      }\n      state = ParseState.EXPECT_VERSION;\n      break;\n    case EXPECT_VERSION:\n      if (!name.equals(\"EDITS_VERSION\")) {\n        throw new InvalidXmlException(\"you must put \" +","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineEditsViewer/OfflineEditsXmlLoader.java#L110-L146","documentation":"When offlineEditsViewer reads an XML edits file (-p xml input or XmlEditsVisitors round-trip), OfflineEditsXmlLoader drives a SAX handler as a strict state machine. endDocument() must find the machine in ParseState.EXPECT_END, reached only after the closing </EDITS> tag has been consumed with a well-formed record sequence. Any other final state throws InvalidXmlException('expecting </EDITS>') — in practice the document ended early, most often a truncated file cut off before the closing tag.","triggerScenarios":"Feeding oev an edits XML file that is truncated (missing or unclosed </EDITS>), or one whose records stopped mid-structure, e.g. partial copy from a crashed scp, log rotation artifact, or manual editing that deleted the tail.","commonSituations":"Copying a large edits XML over a flaky link and getting a short file; regenerating XML by concatenation that dropped the last line; hand-trimming files for test fixtures.","solutions":["Re-generate the XML from the source binary edits log with 'hdfs oev -i <edits> -o out.xml -p xml' rather than repairing by hand.","If the source is gone, restore the tail (at minimum a well-formed sequence of closed records plus </EDITS>) from a backup or snapshot of the XML.","Sanity-check the file first: 'tail -n 5 file.xml' should show </EDITS>, and xmllint --noout reports where well-formedness breaks."],"exampleFix":"<!-- before: file ends abruptly -->\n<RECORD><OPCODE>9</OPCODE><DATA>...unbalanced...\n\n<!-- after: complete document -->\n<EDITS><EDITS_VERSION>-64</EDITS_VERSION>\n  <RECORD><OPCODE>9</OPCODE><DATA>...</DATA></RECORD>\n</EDITS>","handlingStrategy":"try-catch","validationCode":"// Cheap structural pre-check before handing the file to oev\nList<String> tail = Files.readAllLines(Path.of(file)).size() > 5\n    ? Files.readAllLines(Path.of(file)).subList(\n        Files.readAllLines(Path.of(file)).size() - 5,\n        Files.readAllLines(Path.of(file)).size()) : List.of();\nif (tail.stream().noneMatch(l -> l.trim().equals(\"</EDITS>\"))) {\n  throw new IOException(file + \" does not end with </EDITS>; likely truncated\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  OfflineEditsLoader loader = OfflineEditsLoader.createLoader(visitor);\n  loader.loadEdits();\n} catch (InvalidXmlException e) {\n  // SAX-state failure: message names what the machine expected\n  System.err.println(\"Edits XML malformed: \" + e.getMessage()\n      + \" - regenerate with 'hdfs oev -p xml' from the binary edits\");\n}","preventionTips":["Treat oev XML as generated output only: never hand-edit, merge, or truncate it.","After copying large XML dumps, verify size/checksum and that the last line is </EDITS> before processing.","Keep the original binary edits files so any XML can be regenerated."],"tags":["hadoop","hdfs","offline-edits-viewer","xml","parsing"],"backgroundTag":"malformed-xml-document","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}