{"record":{"id":"f252535d812c907a","repo":"prestodb/presto","slug":"invalid-position-s-and-length-s-in-page-with-s","errorCode":null,"errorMessage":"Invalid position %s and length %s in page with %s positions","messagePattern":"Invalid position (.+?) and length (.+?) in page with (.+?) positions","errorType":"exception","errorClass":"java.lang.IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"presto-common/src/main/java/com/facebook/presto/common/Page.java","lineNumber":185,"sourceCode":"\n    /**\n     * Gets the values at the specified position as a single element page.  The method creates independent\n     * copy of the data.\n     */\n    public Page getSingleValuePage(int position)\n    {\n        Block[] singleValueBlocks = new Block[this.blocks.length];\n        for (int i = 0; i < this.blocks.length; i++) {\n            singleValueBlocks[i] = this.blocks[i].getSingleValueBlock(position);\n        }\n        return wrapBlocksWithoutCopy(1, singleValueBlocks);\n    }\n\n    // getRegion() is used to get a sub-page or region of a page based on the given positionOffset and length\n    public Page getRegion(int positionOffset, int length)\n    {\n        if (positionOffset < 0 || length < 0 || positionOffset + length > positionCount) {\n            throw new IndexOutOfBoundsException(format(\"Invalid position %s and length %s in page with %s positions\", positionOffset, length, positionCount));\n        }\n\n        // Avoid creating new objects when region is same as original page\n        if (positionOffset == 0 && length == positionCount) {\n            return this;\n        }\n\n        // Create a new page view with the specified region\n        int channelCount = getChannelCount();\n        Block[] slicedBlocks = new Block[channelCount];\n        for (int i = 0; i < channelCount; i++) {\n            slicedBlocks[i] = blocks[i].getRegion(positionOffset, length);\n        }\n        return wrapBlocksWithoutCopy(length, slicedBlocks);\n    }\n\n    public Page appendColumn(Block block)\n    {","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/Page.java#L167-L203","documentation":"Page.getRegion(positionOffset, length) extracts a sub-page; it throws IndexOutOfBoundsException when positionOffset is negative, length is negative, or positionOffset + length exceeds the page's positionCount. This guards against reading outside the page's valid position range.","triggerScenarios":"Calling page.getRegion(offset, len) with offset < 0, len < 0, or offset+len > page.getPositionCount(), e.g. requesting 1000 rows from a page that only has 500.","commonSituations":"Off-by-one errors in custom page processors/operators, pagination code assuming fixed page sizes larger than the actual final page, downstream operators not checking positionCount before slicing, or stale row counts after filtering.","solutions":["Clamp length: use Math.min(offset + length, page.getPositionCount()) - offset before calling getRegion.","Check the page's actual positionCount via getPositionCount() and compute the region bounds from it.","Fix off-by-one arithmetic in the calling operator or pagination logic.","Add an assertion/unit test that validates offsets against the page size for your custom operator."],"exampleFix":"// before\nPage region = page.getRegion(pageOffset, batchSize);\n// after\nint len = Math.min(batchSize, page.getPositionCount() - pageOffset);\nPage region = len > 0 ? page.getRegion(pageOffset, len) : null;","handlingStrategy":"validation","validationCode":"boolean isValidRegion(Page page, int offset, int length) {\n    return page != null && offset >= 0 && length >= 0 && offset + length <= page.getPositionCount();\n}","typeGuard":"Page safeGetRegion(Page page, int offset, int length) {\n    if (page == null || offset < 0 || length < 0 || offset + length > page.getPositionCount()) {\n        return null;\n    }\n    return page.getRegion(offset, length);\n}","tryCatchPattern":"try {\n    return page.getRegion(offset, length);\n} catch (IndexOutOfBoundsException e) {\n    log.warn(\"Region request [%d,%d] outside page size %d\", offset, length, page.getPositionCount());\n    return page.getPositionCount() > 0 ? page.getRegion(0, page.getPositionCount()) : Page.EMPTY;\n}","preventionTips":["Always derive region bounds from page.getPositionCount(), never from assumed batch sizes.","Clamp length with Math.min for the final page in pagination loops.","Unit-test page slicing against boundary cases (0 rows, exactly 1 row, full page).","Compute offsets in long or double-check arithmetic to avoid overflow producing negative lengths."],"tags":["page","index-out-of-bounds","presto-common"],"backgroundTag":"page-position-out-of-bounds","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}