prestodb/presto · error · PrestoException

ICEBERG_BAD_DATA

ICEBERG_BAD_DATA

Error message

Expecting Page with one channel but got N

What it means

IcebergDeletePageSink's inner appendPage expects a single-channel page containing just the row-position block (it wraps it with the data-file path as an RLE block to build the delete-file row). Any other channel count triggers this ICEBERG_BAD_DATA exception because the page shape is invalid for position deletes.

Source

Thrown at presto-iceberg/src/main/java/com/facebook/presto/iceberg/delete/IcebergDeletePageSink.java:197

        {
            this.writer = createWriter();
        }

        /**
         * @param page Only one channel. It contains the list of row positions to delete.
         */
        public void appendPage(Page page)
        {
            if (page.getChannelCount() == 1) {
                hdfsEnvironment.doAs(session.getUser(), () -> {
                    Block[] blocks = new Block[2];
                    blocks[0] = new RunLengthEncodedBlock(nativeValueToBlock(VarcharType.VARCHAR, utf8Slice(dataFile)), page.getPositionCount());
                    blocks[1] = page.getBlock(0);
                    writer.appendRows(new Page(blocks));
                });
            }
            else {
                throw new PrestoException(ICEBERG_BAD_DATA, "Expecting Page with one channel but got " + page.getChannelCount());
            }
        }

        public IcebergFileWriter getWriter()
        {
            return writer;
        }

        public long getSystemMemoryUsage()
        {
            return writer.getSystemMemoryUsage();
        }

        private IcebergFileWriter createWriter()
        {
            return fileWriterFactory.createFileWriter(
                    outputPath,
                    positionDeleteSchema,

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Pass a page with exactly one channel holding the delete positions (BIGINT); the sink adds the file path itself.
  2. If your page already has path+position, drop the path channel before appending.
  3. Check upstream operators for an accidental extra projection column feeding the delete sink.

Example fix

// before
sink.appendPage(new Page(positionBlock, pathBlock));
// after
sink.appendPage(new Page(positionBlock)); // only the position channel
Defensive patterns

Strategy: validation

Validate before calling

if (page.getChannelCount() != 1) {
    throw new IllegalArgumentException("Delete sink expects a single position channel, got " + page.getChannelCount());
}

Type guard

boolean isSingleChannelPositionPage(Page page) {
    return page.getChannelCount() == 1 && page.getBlock(0) instanceof BigintBlock;
}

Try / catch

try { sink.appendPage(page); } catch (PrestoException e) { if (e.getErrorCode() == ICEBERG_BAD_DATA.toErrorCode()) { /* rebuild page with one channel */ } throw e; }

Prevention

When it happens

Trigger: Calling appendPage on the delete sink with a Page whose channel count is not 1 (e.g. page already contains path+position columns, or an empty/misconstructed page).

Common situations: Custom delete-writing code passing pages with (path,pos) pairs already merged; a plan bug upstream producing extra columns; misuse of the internal sink API.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/2116d0acc175ea78. Report an issue: GitHub.