{"record":{"id":"9332a795244de241","repo":"apache/hadoop","slug":"only-read-actualdiffs-1-diffs-out-of-expect","errorCode":null,"errorMessage":"Only read ${actualDiffs + 1} diffs out of ${expectedDiffs}","messagePattern":"Only read (.+?) diffs out of (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineImageViewer/OfflineImageReconstructor.java","lineNumber":1448,"sourceCode":"      Long inodeId = dirDiffHeader.removeChildLong(\n          SNAPSHOT_DIFF_SECTION_INODE_ID);\n      if (inodeId == null) {\n        throw new IOException(\"<dirDiffEntry> contained no <inodeId> entry.\");\n      }\n      headerBld.setInodeId(inodeId);\n      Integer expectedDiffs = dirDiffHeader.removeChildInt(\n          SNAPSHOT_DIFF_SECTION_COUNT);\n      if (expectedDiffs == null) {\n        throw new IOException(\"<dirDiffEntry> contained no <count> entry.\");\n      }\n      headerBld.setNumOfDiff(expectedDiffs);\n      dirDiffHeader.verifyNoRemainingKeys(\"dirDiffEntry\");\n      headerBld.build().writeDelimitedTo(out);\n      for (int actualDiffs = 0; actualDiffs < expectedDiffs; actualDiffs++) {\n        try {\n          expectTag(SNAPSHOT_DIFF_SECTION_DIR_DIFF, false);\n        } catch (IOException e) {\n          throw new IOException(\"Only read \" + (actualDiffs + 1) +\n              \" diffs out of \" + expectedDiffs, e);\n        }\n        Node dirDiff = new Node();\n        loadNodeChildren(dirDiff, \"dirDiff fields\");\n        FsImageProto.SnapshotDiffSection.DirectoryDiff.Builder bld =\n            FsImageProto.SnapshotDiffSection.DirectoryDiff.newBuilder();\n        Integer snapshotId = dirDiff.removeChildInt(\n            SNAPSHOT_DIFF_SECTION_SNAPSHOT_ID);\n        if (snapshotId != null) {\n          bld.setSnapshotId(snapshotId);\n        }\n        Integer childrenSize = dirDiff.removeChildInt(\n            SNAPSHOT_DIFF_SECTION_CHILDREN_SIZE);\n        if (childrenSize == null) {\n          throw new IOException(\"Expected to find <childrenSize> in \" +\n              \"<dirDiff> section.\");\n        }\n        bld.setIsSnapshotRoot(dirDiff.removeChildBool(","sourceCodeStart":1430,"sourceCodeEnd":1466,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineImageViewer/OfflineImageReconstructor.java#L1430-L1466","documentation":"While reading the <count>-declared <dirDiff> children of a <dirDiffEntry>, expectTag(\"dirDiff\") failed before the declared number was consumed, and the cause is re-wrapped with this message. Note an off-by-one quirk: the message prints actualDiffs+1, i.e. one more than the number of diffs successfully read, because it counts the failed iteration. The true reason (wrong tag, premature end event, etc.) is in the chained cause.","triggerScenarios":"<count> larger than the actual number of <dirDiff> elements in the entry, or a malformed <dirDiff> that makes the stream reader hit an unexpected event mid-loop; also entries truncated by line-based editing.","commonSituations":"Hand-edited entries where diffs were deleted without updating <count>; scripts that append <dirDiff> blocks but never recompute the count; copy-paste of diff blocks between entries.","solutions":["Read the chained cause to see what the parser hit instead of <dirDiff>","Make <count> equal the number of <dirDiff> elements actually present in that <dirDiffEntry> (mind the message's off-by-one when interpreting it)","Restore any <dirDiff> entries that were deleted or truncated","Pre-validate every <dirDiffEntry> with a streaming count check before reconstructing"],"exampleFix":"<!-- before: count says 3, entry holds 2 -->\n<dirDiffEntry><inodeId>16386</inodeId><count>3</count>\n  <dirDiff>...</dirDiff><dirDiff>...</dirDiff>\n</dirDiffEntry>\n<!-- after -->\n<dirDiffEntry><inodeId>16386</inodeId><count>2</count>\n  <dirDiff>...</dirDiff><dirDiff>...</dirDiff>\n</dirDiffEntry>","handlingStrategy":"validation","validationCode":"# python: <count> must equal number of <dirDiff> children per dirDiffEntry\n# (also guards the follow-on 'Only read N diffs' failure)\nimport xml.etree.ElementTree as ET\n\ndef validate(path):\n    for el in ET.iterparse(path, events=('end',)):\n        e = el if el.tag == 'dirDiffEntry' else None\n        if e is not None:\n            c = e.find('count')\n            if c is None or int(c.text) != len(e.findall('dirDiff')):\n                return False\n    return True","typeGuard":null,"tryCatchPattern":"# on 'Only read N diffs out of M' inspect the chained cause in stderr,\n# correct <count> or restore diffs, delete partial output, re-run","preventionTips":["Interpret the message knowing it reports one MORE than actually read (off-by-one)","Update <count> whenever diffs are added/removed","Stream-validate all entries before ReverseXML","Never resume from a partially written output image"],"tags":["hdfs","oiv","fsimage","reversexml","snapshot-diff","count-mismatch"],"backgroundTag":"xml-entry-count-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}