{"record":{"id":"89f03d411e6a2270","repo":"apache/druid","slug":"unexpected-end-of-first-adapter","errorCode":null,"errorMessage":"Unexpected end of first adapter","messagePattern":"Unexpected end of first adapter","errorType":"validation","errorClass":"SegmentValidationException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/IndexIO.java","lineNumber":198,"sourceCode":"      while (it1.moveToNext()) {\n        if (!it2.moveToNext()) {\n          throw new SegmentValidationException(\"Unexpected end of second adapter\");\n        }\n        final RowPointer rp1 = it1.getPointer();\n        final RowPointer rp2 = it2.getPointer();\n        ++row;\n        if (rp1.getRowNum() != rp2.getRowNum()) {\n          throw new SegmentValidationException(\"Row number mismatch: [%d] vs [%d]\", rp1.getRowNum(), rp2.getRowNum());\n        }\n        try {\n          validateRowValues(rp1, adapter1, rp2, adapter2);\n        }\n        catch (SegmentValidationException ex) {\n          throw new SegmentValidationException(ex, \"Validation failure on row %d: [%s] vs [%s]\", row, rp1, rp2);\n        }\n      }\n      if (it2.moveToNext()) {\n        throw new SegmentValidationException(\"Unexpected end of first adapter\");\n      }\n      if (row != adapter1.getNumRows()) {\n        throw new SegmentValidationException(\n            \"Actual Row count mismatch. Expected [%d] found [%d]\",\n            row,\n            adapter1.getNumRows()\n        );\n      }\n    }\n  }\n\n  public QueryableIndex loadIndex(File inDir) throws IOException\n  {\n    return loadIndex(inDir, false, SegmentLazyLoadFailCallback.NOOP);\n  }\n\n  public QueryableIndex loadIndex(File inDir, boolean lazy, SegmentLazyLoadFailCallback loadFailed) throws IOException\n  {","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/IndexIO.java#L180-L216","documentation":"After the row loop, validateTwoSegments checks whether the second iterator still has rows left (it2.moveToNext() true) after the first was exhausted. If so, the second adapter has MORE rows than the first, and this SegmentValidationException ('Unexpected end of first adapter') is thrown.","triggerScenarios":"it1 exhausted while it2.moveToNext() still succeeds — first adapter ended early relative to the second, indicating row-count or iteration mismatch.","commonSituations":"First segment truncated/corrupt so its iterator ends prematurely; custom adapter over-reporting or under-yielding rows; comparing segments from different input sets.","solutions":["Re-verify both segments' numRows (the earlier count check should have caught this; investigate if counts matched but iteration differed).","Check the first segment's files for truncation/corruption and restore from deep storage if needed.","Re-ingest the first segment from source data and re-validate.","Debug any custom RowIterator for the first adapter for premature termination."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  io.validateTwoSegments(adapter1, adapter2);\n} catch (SegmentValidationException e) {\n  if (e.getMessage().contains(\"Unexpected end of first adapter\")) {\n    log.error(\"First adapter exhausted early — possible truncation: %s\", e.getMessage());\n  }\n  throw e;\n}","preventionTips":["Check declared numRows vs iterated rows on both adapters before full validation.","Verify segment files were fully written/copied (checksums, sizes).","Treat interrupted segment operations as suspect and re-fetch from deep storage.","Test custom RowIterators for premature termination."],"tags":["segment-validation","iteration","corruption"],"backgroundTag":"internal-invariant-violation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}