apache/hadoop · error · IOException

<dirDiffEntry> contained no <inodeId> entry.

Error message

<dirDiffEntry> contained no <inodeId> entry.

What it means

A <dirDiffEntry> header in <SnapshotDiffSection> is missing its <inodeId> child, which the protobuf DiffEntry requires to identify the directory the diffs belong to. The reconstructor loads the entry's header fields (everything up to the first <dirDiff> terminator) and removeChildLong("inodeId") returned null.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineImageViewer/OfflineImageReconstructor.java:1433

          processFileDiffEntry();
        } else {
          throw new IOException("SnapshotDiffSection contained unexpected " +
              "tag " + tagName);
        }
      }
      recordSectionLength(SectionName.SNAPSHOT_DIFF.name());
    }

    private void processDirDiffEntry() throws IOException {
      LOG.debug("Processing dirDiffEntry");
      DiffEntry.Builder headerBld = DiffEntry.newBuilder();
      headerBld.setType(DiffEntry.Type.DIRECTORYDIFF);
      Node dirDiffHeader = new Node();
      loadNodeChildren(dirDiffHeader, "dirDiffEntry fields", "dirDiff");
      Long inodeId = dirDiffHeader.removeChildLong(
          SNAPSHOT_DIFF_SECTION_INODE_ID);
      if (inodeId == null) {
        throw new IOException("<dirDiffEntry> contained no <inodeId> entry.");
      }
      headerBld.setInodeId(inodeId);
      Integer expectedDiffs = dirDiffHeader.removeChildInt(
          SNAPSHOT_DIFF_SECTION_COUNT);
      if (expectedDiffs == null) {
        throw new IOException("<dirDiffEntry> contained no <count> entry.");
      }
      headerBld.setNumOfDiff(expectedDiffs);
      dirDiffHeader.verifyNoRemainingKeys("dirDiffEntry");
      headerBld.build().writeDelimitedTo(out);
      for (int actualDiffs = 0; actualDiffs < expectedDiffs; actualDiffs++) {
        try {
          expectTag(SNAPSHOT_DIFF_SECTION_DIR_DIFF, false);
        } catch (IOException e) {
          throw new IOException("Only read " + (actualDiffs + 1) +
              " diffs out of " + expectedDiffs, e);
        }
        Node dirDiff = new Node();

View on GitHub (pinned to 2add963021)

Solutions

  1. Add <inodeId>NUMBER</inodeId> as the first header child of the affected <dirDiffEntry>
  2. Verify <inodeId> sits before the first <dirDiff> element - anything after it is treated as diff content, not header
  3. Check spelling/case: the tag must be exactly 'inodeId'
  4. Regenerate the XML with a same-version oiv if the section is beyond manual repair

Example fix

<!-- before -->
<dirDiffEntry><count>2</count><dirDiff>...</dirDiff></dirDiffEntry>
<!-- after -->
<dirDiffEntry><inodeId>16386</inodeId><count>2</count><dirDiff>...</dirDiff></dirDiffEntry>
Defensive patterns

Strategy: validation

Validate before calling

# python: each dirDiffEntry header must contain <inodeId> before the first <dirDiff>
import xml.etree.ElementTree as ET

def dir_entries_have_inodeid(path):
    for ev, el in ET.iterparse(path, events=('end',)):
        if el.tag == 'dirDiffEntry' and el.find('inodeId') is None:
            return False
    return True

Try / catch

if oiv_reverse_xml_fails():
    # stderr pinpoints '<dirDiffEntry> contained no <inodeId> entry.'
    # fix that element, delete the partial output, retry once
    ...

Prevention

When it happens

Trigger: A <dirDiffEntry> whose <inodeId> child was omitted, renamed, or misspelled (the parser matches the exact tag 'inodeId', case-sensitive), or whose header fields were accidentally nested inside the first <dirDiff>.

Common situations: Hand-edited entries where the ID was dropped; scripts generating dir-diff entries from a different schema; reordering that moved <inodeId> below the <dirDiff> terminator so it lands in the diff body instead of the header.

Related errors


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