{"record":{"id":"8655cafa53802ce8","repo":"apache/pulsar","slug":"entry-index-messageentryid-beyond-lastentryid","errorCode":null,"errorMessage":"Entry index: ${messageEntryId} beyond lastEntryId: ${lastEntryId}","messagePattern":"Entry index: (.+?) beyond lastEntryId: (.+?)","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"tiered-storage/jcloud/src/main/java/org/apache/bookkeeper/mledger/offload/jcloud/impl/OffloadIndexBlockImpl.java","lineNumber":108,"sourceCode":"\n    public void recycle() {\n        dataObjectLength = -1;\n        dataHeaderLength = -1;\n        segmentMetadata = null;\n        indexEntries.clear();\n        indexEntries = null;\n        if (recyclerHandle != null) {\n            recyclerHandle.recycle(this);\n        }\n    }\n\n    @Override\n    public OffloadIndexEntry getIndexEntryForEntry(long messageEntryId) throws IOException {\n        if (messageEntryId > segmentMetadata.getLastEntryId()) {\n            log.warn().attr(\"entryId\", messageEntryId)\n                    .attr(\"lastEntryId\", segmentMetadata.getLastEntryId())\n                    .log(\"Requested entry beyond lastEntryId\");\n            throw new IndexOutOfBoundsException(\"Entry index: \" + messageEntryId\n                + \" beyond lastEntryId: \" + segmentMetadata.getLastEntryId());\n        }\n        // find the greatest mapping Id whose entryId <= messageEntryId\n        return this.indexEntries.floorEntry(messageEntryId).getValue();\n    }\n\n    @Override\n    public int getEntryCount() {\n        return this.indexEntries.size();\n    }\n\n    @Override\n    public LedgerMetadata getLedgerMetadata() {\n        return this.segmentMetadata;\n    }\n\n    @Override\n    public long getDataObjectLength() {","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/tiered-storage/jcloud/src/main/java/org/apache/bookkeeper/mledger/offload/jcloud/impl/OffloadIndexBlockImpl.java#L90-L126","documentation":"getIndexEntryForEntry looks up the data-block location of a ledger entry in the offload index. If the requested entry id exceeds the segment metadata's lastEntryId, the entry cannot exist in this offloaded segment, so an IndexOutOfBoundsException is thrown after a warning log. This is a caller-input validation failure, not corruption.","triggerScenarios":"Calling getIndexEntryForEntry(messageEntryId) with an entry id greater than segmentMetadata.getLastEntryId() — e.g. requesting entries that were written to the ledger after it was offloaded, or passing a wrong/uninitialized entry id.","commonSituations":"Reading entries from a ledger that has continued appending after offload without re-reading them from BookKeeper; cursor cache assuming offloaded data covers the whole ledger; off-by-one or wrong-segment logic when iterating entries.","solutions":["Check entryId against segment metadata lastEntryId before calling, and read newer entries from BookKeeper instead","Re-offload the ledger if data written after the previous offload should now be offloaded","Ensure callers iterate only entry ids within the offloaded segment's range","Fix off-by-one logic: valid ids are <= lastEntryId in the segment"],"exampleFix":"// before: blind lookup\nOffloadIndexEntry e = index.getIndexEntryForEntry(entryId);\n// after: bounds-check and fall back to BookKeeper\nif (entryId > index.getSegmentMetadata().getLastEntryId()) {\n    return readEntryFromBookKeeper(ledgerId, entryId);\n}\nOffloadIndexEntry e = index.getIndexEntryForEntry(entryId);","handlingStrategy":"validation","validationCode":"if (messageEntryId > index.getSegmentMetadata().getLastEntryId()) {\n    // entry not offloaded; must be read from BookKeeper instead\n    return readFromBookKeeper(ledgerId, messageEntryId);\n}","typeGuard":null,"tryCatchPattern":"try {\n    OffloadIndexEntry e = index.getIndexEntryForEntry(messageEntryId);\n} catch (IndexOutOfBoundsException e) {\n    // fall back to BookKeeper for entries beyond the offloaded segment\n}","preventionTips":["Track the offloaded entry range per ledger in the reader","Route entries beyond lastEntryId to BookKeeper reads","Re-offload after significant post-offload writes if storage reads are needed","Avoid assuming offloaded data covers the full ledger"],"tags":["index-out-of-bounds","input-validation","tiered-storage"],"backgroundTag":"entry-index-out-of-range","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}