apache/hadoop · error · IOException

Failed to find <numInodes> in INodeSection.

Error message

Failed to find <numInodes> in INodeSection.

What it means

INodeSectionProcessor reads the section header into a Node and requires INODE_SECTION_NUM_INODES (<numInodes>); the value is stored in the protobuf header and drives the loop that consumes exactly that many <inode> entries. Missing it means the header was edited down, the element was renamed, or the XML comes from a dialect that does not carry it.

Source

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

    }
  }

  private class INodeSectionProcessor implements SectionProcessor {
    static final String NAME = "INodeSection";

    @Override
    public void process() throws IOException {
      Node headerNode = new Node();
      loadNodeChildren(headerNode, "INodeSection fields", "inode");
      INodeSection.Builder b =  INodeSection.newBuilder();
      Long lval = headerNode.removeChildLong(INODE_SECTION_LAST_INODE_ID);
      if (lval != null)  {
        b.setLastInodeId(lval);
      }
      Integer expectedNumINodes =
          headerNode.removeChildInt(INODE_SECTION_NUM_INODES);
      if (expectedNumINodes == null) {
        throw new IOException("Failed to find <numInodes> in INodeSection.");
      }
      b.setNumInodes(expectedNumINodes);
      INodeSection s = b.build();
      s.writeDelimitedTo(out);
      headerNode.verifyNoRemainingKeys("INodeSection");
      int actualNumINodes = 0;
      while (actualNumINodes < expectedNumINodes) {
        try {
          expectTag(INODE_SECTION_INODE, false);
        } catch (IOException e) {
          throw new IOException("Only found " + actualNumINodes +
              " <inode> entries out of " + expectedNumINodes, e);
        }
        actualNumINodes++;
        Node inode = new Node();
        loadNodeChildren(inode, "INode fields");
        INodeSection.INode.Builder inodeBld = processINodeXml(inode);
        inodeBld.build().writeDelimitedTo(out);

View on GitHub (pinned to 2add963021)

Solutions

  1. Set <numInodes> to the exact number of <inode> elements present in the section
  2. Regenerate the dump and prune with a DOM/XPath tool that recomputes counts
  3. Validate the pair before running: xmllint --xpath 'count(//inode)' img.xml must equal the <numInodes> text

Example fix

<!-- before -->
<INodeSection><lastInodeId>16401</lastInodeId></INodeSection>

<!-- after -->
<INodeSection><lastInodeId>16401</lastInodeId><numInodes>1</numInodes><inode>...</inode></INodeSection>
Defensive patterns

Strategy: validation

Validate before calling

declared=$(xmllint --xpath 'string(//INodeSection/numInodes)' fsimage.xml 2>/dev/null)
actual=$(xmllint --xpath 'count(//inode)' fsimage.xml)
case "$declared" in ''|*[!0-9]*) echo '<numInodes> missing or non-numeric'; exit 1;; esac
[ "$declared" = "$actual" ] || { echo "numInodes=$declared vs $actual entries"; exit 1; }

Prevention

When it happens

Trigger: ReverseXML after <numInodes> was deleted or renamed inside <INodeSection>, or two INodeSections merged without combining their headers.

Common situations: Namespace-pruning attempts by editing XML; version-skewed dumps; copy-paste of section bodies without headers.

Related errors


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