{"record":{"id":"be54ddb8d1b66e53","repo":"apache/hadoop","slug":"only-read-actualnumsnapshots-snapshot-entries","errorCode":null,"errorMessage":"Only read ${actualNumSnapshots} <snapshot> entries out of ${expectedNumSnapshots}","messagePattern":"Only read (.+?) <snapshot> entries 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":1372,"sourceCode":"      while (true) {\n        Node sd = header.removeChild(SNAPSHOT_SECTION_SNAPSHOT_TABLE_DIR);\n        if (sd == null) {\n          break;\n        }\n        Long dir;\n        while ((dir = sd.removeChildLong(SNAPSHOT_SECTION_DIR)) != null) {\n          // Add all snapshottable directories, one by one\n          bld.addSnapshottableDir(dir);\n        }\n      }\n      header.verifyNoRemainingKeys(\"SnapshotSection\");\n      bld.build().writeDelimitedTo(out);\n      int actualNumSnapshots = 0;\n      while (actualNumSnapshots < expectedNumSnapshots) {\n        try {\n          expectTag(SNAPSHOT_SECTION_SNAPSHOT, false);\n        } catch (IOException e) {\n          throw new IOException(\"Only read \" + actualNumSnapshots +\n              \" <snapshot> entries out of \" + expectedNumSnapshots, e);\n        }\n        actualNumSnapshots++;\n        Node snapshot = new Node();\n        loadNodeChildren(snapshot, \"snapshot fields\");\n        FsImageProto.SnapshotSection.Snapshot.Builder s =\n            FsImageProto.SnapshotSection.Snapshot.newBuilder();\n        Integer snapshotId = snapshot.removeChildInt(SECTION_ID);\n        if (snapshotId == null) {\n          throw new IOException(\"<snapshot> section was missing <id>\");\n        }\n        s.setSnapshotId(snapshotId);\n        Node snapshotRoot = snapshot.removeChild(SNAPSHOT_SECTION_ROOT);\n        INodeSection.INode.Builder inodeBld = processINodeXml(snapshotRoot);\n        s.setRoot(inodeBld);\n        s.build().writeDelimitedTo(out);\n      }\n      expectTagEnd(SNAPSHOT_SECTION_NAME);","sourceCodeStart":1354,"sourceCodeEnd":1390,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineImageViewer/OfflineImageReconstructor.java#L1354-L1390","documentation":"Thrown by Hadoop's ReverseXML processor (OfflineImageReconstructor, invoked via `hdfs oiv -processor ReverseXML`) while rebuilding a binary fsimage from an XML dump. The <SnapshotSection> header declares <snapshotCount>N</snapshotCount>; the reconstructor loops N times calling expectTag(\"snapshot\"), and when that read fails (wrong tag, premature end event, XMLStreamException) the failure is re-wrapped with this message. The real reason is always in the chained cause exception.","triggerScenarios":"Running `hdfs oiv -processor ReverseXML -i dump.xml -o fsimage.out` where <snapshotCount> exceeds the number of <snapshot> elements actually present, or where a <snapshot> entry is malformed so expectTag hits an unexpected event mid-loop.","commonSituations":"Disaster-recovery workflows that hand-edit fsimage XML then reconstitute it; test harnesses synthesizing <SnapshotSection> blocks; XML dumps produced by an oiv from a different Hadoop release; files truncated during transfer or by editors on huge images.","solutions":["Read the chained IOException cause first - it names the actual tag mismatch or stream error that stopped the loop","If the XML was hand-edited, make <snapshotCount> equal the real number of <snapshot> elements (or restore the missing entries)","Regenerate the XML from the original binary fsimage with a same-version oiv (`hdfs oiv -processor XML`) instead of editing it","Stream-count <snapshot> elements vs <snapshotCount> and run xmllint --noout before ReverseXML"],"exampleFix":"<!-- before: header promises 5 snapshots, only 3 exist -->\n<SnapshotSection>\n  <snapshotCount>5</snapshotCount>\n  <snapshottableDir>16386</snapshottableDir>\n  <snapshot><id>101</id>...</snapshot>\n  <snapshot><id>102</id>...</snapshot>\n  <snapshot><id>103</id>...</snapshot>\n</SnapshotSection>\n<!-- after: count matches reality -->\n<SnapshotSection>\n  <snapshotCount>3</snapshotCount>\n  ...","handlingStrategy":"validation","validationCode":"# python: verify snapshotCount matches <snapshot> entries before ReverseXML\nimport xml.etree.ElementTree as ET\n\ndef snapshot_counts_ok(path):\n    declared, actual = None, 0\n    for ev, el in ET.iterparse(path, events=('end',)):\n        if el.tag == 'snapshotCount' and declared is None:\n            declared = int(el.text)\n        elif el.tag == 'snapshot' and declared is not None:\n            actual += 1\n    return declared is not None and declared == actual","typeGuard":null,"tryCatchPattern":"# wrap the CLI; never reuse the partial output file after a failure\nimport subprocess\nrc = subprocess.call(['hdfs','oiv','-processor','ReverseXML','-i','dump.xml','-o','out.img'])\nif rc != 0:\n    # stderr carries 'Only read N <snapshot> entries...' plus the cause chain\n    raise RuntimeError('fsimage reconstruction failed; inspect stderr cause chain')","preventionTips":["Never hand-edit snapshotCount without recounting <snapshot> elements","Regenerate XML with the same oiv version that will reconstruct it","Run xmllint --noout plus a streaming count check before ReverseXML","Treat the chained cause, not the wrapper message, as the root cause"],"tags":["hdfs","oiv","fsimage","reversexml","snapshot","count-mismatch"],"backgroundTag":"xml-entry-count-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}