apache/hadoop · error · InvalidXmlException

expected </OPCODE>

Error message

expected </OPCODE>

What it means

Thrown from endElement() in EXPECT_OPCODE state: a <RECORD> was opened but the next element-close event was not </OPCODE>. Every <RECORD> must begin with exactly <OPCODE>OP_XXX</OPCODE> (its text is resolved via FSEditLogOpCodes.valueOf); a record that closes before a complete OPCODE element is rejected.

Source

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

      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:
      if (!name.equals("OPCODE")) {
        throw new InvalidXmlException("expected </OPCODE>");
      }
      opCode = FSEditLogOpCodes.valueOf(str);
      state = ParseState.EXPECT_DATA;
      break;
    case EXPECT_DATA:
      throw new InvalidXmlException("expected <DATA/>");
    case HANDLE_DATA:
      stanza.setValue(str);
      if (stanzaStack.empty()) {
        if (!name.equals("DATA")) {
          throw new InvalidXmlException("expected </DATA>");
        }
        state = ParseState.EXPECT_RECORD;
        FSEditLogOp op = opCache.get(opCode);
        opCode = null;
        try {
          op.decodeXml(stanza);
          stanza = null;

View on GitHub (pinned to 2add963021)

Solutions

  1. Delete empty <RECORD/> or <RECORD></RECORD> blocks entirely — records are optional, but when present they must be complete.
  2. Ensure every record reads <RECORD><OPCODE>OP_...</OPCODE><DATA>...</DATA></RECORD>.
  3. Regenerate the file with hdfs oev rather than filtering the XML by hand.

Example fix

// before
<RECORD>
  <OPCODE>OP_ADD</OPCODE>
</RECORD>
<RECORD/>

// after
<RECORD>
  <OPCODE>OP_ADD</OPCODE>
  <DATA>...</DATA>
</RECORD>
Defensive patterns

Strategy: try-catch

Validate before calling

private static boolean recordsAreComplete(String xml) {
  // every RECORD must contain an OPCODE element
  for (String rec : xml.split("(?s)(?=<RECORD>)")) {
    if (rec.startsWith("<RECORD") && !rec.contains("<OPCODE>")) return false;
  }
  return true;
}

Try / catch

try {
  loader.loadEdits();
} catch (InvalidXmlException e) {
  // a <RECORD> lacked <OPCODE>...</OPCODE>; drop or complete empty records
  LOG.error("Incomplete record in edits XML: {}", e.getMessage());
}

Prevention

When it happens

Trigger: An empty or self-closed record element: <RECORD/> or <RECORD></RECORD> — the </RECORD> close fires while the loader still waits for <OPCODE>. Also any record whose first child closes with a name other than OPCODE.

Common situations: Hand-deleting record bodies but leaving empty <RECORD> shells; line-based filtering tools that drop the opcode line but keep the record tags; template-generated edits files with unfilled records.

Related errors


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