apache/hadoop · error · InvalidXmlException

expected </EDITS_VERSION>

Error message

expected </EDITS_VERSION>

What it means

Thrown from endElement() when the parser is in EXPECT_VERSION state (right after <EDITS> opened) and the element being closed is not EDITS_VERSION. The loader demands that the first child of <EDITS> be exactly <EDITS_VERSION>number</EDITS_VERSION>, whose text is parsed as an int layout version (e.g. -63) and passed to visitor.start(). A misspelled, wrongly-cased, or namespace-prefixed version tag breaks this check.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineEditsViewer/OfflineEditsXmlLoader.java:190

      stanzaStack.push(parent);
      stanza = child;
      parent.addChild(name, child);
      break;
    case EXPECT_END:
      throw new InvalidXmlException("not expecting anything after </EDITS>");
    }
  }
  
  @Override
  public void endElement (String uri, String name, String qName) {
    String str = XMLUtils.unmangleXmlString(cbuf.toString(), false).trim();
    cbuf = new StringBuilder();
    switch (state) {
    case EXPECT_EDITS_TAG:
      throw new InvalidXmlException("expected <EDITS/>");
    case EXPECT_VERSION:
      if (!name.equals("EDITS_VERSION")) {
        throw new InvalidXmlException("expected </EDITS_VERSION>");
      }
      try {
        int version = Integer.parseInt(str);
        visitor.start(version);
      } catch (IOException e) {
        // Can't throw IOException from a SAX method, sigh.
        throw new RuntimeException(e);
      }
      state = ParseState.EXPECT_RECORD;
      break;
    case EXPECT_RECORD:
      if (name.equals("EDITS")) {
        state = ParseState.EXPECT_END;
      } else if (!name.equals("RECORD")) {
        throw new InvalidXmlException("expected </EDITS> or </RECORD>");
      }
      break;
    case EXPECT_OPCODE:

View on GitHub (pinned to 2add963021)

Solutions

  1. Make the first child of <EDITS> exactly <EDITS_VERSION>-63</EDITS_VERSION> (or the layout version your target format expects), spelled identically on open and close.
  2. Regenerate the file with hdfs oev -i <binary edits> -p XML -o edits.xml instead of editing it.
  3. Remove namespace prefixes or attributes from the header tags; the state machine compares raw local names.

Example fix

// before
<EDITS>
  <EDITS-VERSION>-63</EDITS-VERSION>
  ...

// after
<EDITS>
  <EDITS_VERSION>-63</EDITS_VERSION>
  ...
Defensive patterns

Strategy: try-catch

Validate before calling

private static boolean hasValidHeader(File f) throws IOException {
  byte[] b = Files.readAllBytes(f.toPath());
  String head = new String(b, 0, (int) Math.min(4096, b.length), StandardCharsets.UTF_8).trim();
  return head.matches("(?s)\\A<\\?xml[^>]*\\?>\\s*<EDITS>\\s*<EDITS_VERSION>-?\\d+</EDITS_VERSION>.*");
}

Try / catch

try {
  loader.loadEdits();
} catch (InvalidXmlException e) {
  // Header tag wrong: expected first child <EDITS_VERSION>nn</EDITS_VERSION>
  throw new IOException("Bad OEV XML header in " + file + ": " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: An XML edits file in which the element inside <EDITS> is not named exactly EDITS_VERSION (e.g. <EDITS-VERSION>, <edits_version>, or a prefixed tag), so name.equals("EDITS_VERSION") fails on close. Also reachable when header elements are reordered or renamed by naive XML rewriters.

Common situations: Hand-editing or programmatically regenerating oev XML and getting the header tag wrong; XSLT transforms or pretty-printers that rename or namespace elements; merging output from a different tool version.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/0e55f8c78ca6172e. Report an issue: GitHub.