{"record":{"id":"eb5eed8c680f5b66","repo":"prestodb/presto","slug":"corrupt-page","errorCode":"CORRUPT_PAGE","errorMessage":"delegate page channels do not match expected number of channels","messagePattern":"delegate page channels do not match expected number of channels","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-iceberg/src/main/java/com/facebook/presto/iceberg/changelog/ChangelogPageSource.java","lineNumber":130,"sourceCode":"        return delegate.getSystemMemoryUsage();\n    }\n\n    @Override\n    public void close()\n            throws IOException\n    {\n        delegate.close();\n    }\n\n    public enum ChangelogSchemaColumns\n    {\n        OPERATION((source, page) -> RunLengthEncodedBlock.create(VARCHAR, Slices.utf8Slice(source.changelogSplitInfo.getOperation().toString()), page.getPositionCount())),\n        ORDINAL((source, page) -> RunLengthEncodedBlock.create(BIGINT, source.changelogSplitInfo.getOrdinal(), page.getPositionCount())),\n        SNAPSHOTID((source, page) -> RunLengthEncodedBlock.create(BIGINT, source.changelogSplitInfo.getSnapshotId(), page.getPositionCount())),\n\n        ROWDATA((source, page) -> {\n            if (source.innerRowType.getFields().size() != page.getChannelCount()) {\n                throw new PrestoException(CORRUPT_PAGE, \"delegate page channels do not match expected number of channels\");\n            }\n            Block[] channels = new Block[page.getChannelCount()];\n            for (int i = 0; i < page.getChannelCount(); i++) {\n                channels[i] = page.getBlock(i);\n            }\n            return RowBlock.fromFieldBlocks(page.getPositionCount(), Optional.empty(), channels);\n        });\n\n        private final ChangelogUtil.Function2<ChangelogPageSource, Page, Block> blockSupplier;\n\n        ChangelogSchemaColumns(ChangelogUtil.Function2<ChangelogPageSource, Page, Block> blockSupplier)\n        {\n            this.blockSupplier = blockSupplier;\n        }\n\n        public Block getBlock(ChangelogPageSource pageSource, Page page)\n        {\n            return blockSupplier.apply(pageSource, page);","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-iceberg/src/main/java/com/facebook/presto/iceberg/changelog/ChangelogPageSource.java#L112-L148","documentation":"The ChangelogPageSource's ROWDATA column converter expects the delegate page's channel count to exactly equal the number of fields in the changelog's inner row type, since channels are wrapped into a RowBlock. A mismatch means the underlying page doesn't correspond to the declared row schema, so CORRUPT_PAGE is thrown to avoid producing a malformed row block.","triggerScenarios":"getNextPage on a changelog split where source.innerRowType.getFields().size() differs from page.getChannelCount() — e.g. stale split metadata after schema evolution, or a delegate source emitting extra/missing columns.","commonSituations":"Iceberg table schema changed (columns added/dropped) between split planning and execution; reading a changelog with an outdated cached schema.","solutions":["Re-run the query so splits are re-planned against the current table schema.","Verify the changelog split's innerRowType matches the actual file schema; fix metadata caching if it doesn't.","Check for schema-evolution operations (ADD/DROP COLUMN) concurrent with the changelog query."],"exampleFix":"// before: channels from stale schema\nRowBlock.fromFieldBlocks(page.getPositionCount(), Optional.empty(), channels);\n// after: guard before building\nif (source.innerRowType.getFields().size() != page.getChannelCount()) {\n    throw new PrestoException(CORRUPT_PAGE, \"delegate page channels do not match expected number of channels\");\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"boolean pageMatchesRowType(Page page, RowType innerRowType) {\n    return page.getChannelCount() == innerRowType.getFields().size();\n}","tryCatchPattern":"try { return pageSource.getNextPage(); } catch (PrestoException e) { if (e.getErrorCode() == CORRUPT_PAGE.toErrorCode()) { /* re-plan split against current schema */ } throw e; }","preventionTips":["Avoid concurrent schema evolution during changelog queries","Re-plan queries after ADD/DROP COLUMN","Verify split metadata freshness against current table schema"],"tags":["iceberg","changelog","corrupt-page","schema-mismatch"],"backgroundTag":"channel-count-mismatch","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"}