apache/flink · error · UnsupportedOperationException

Only support seek at first.

Error message

Only support seek at first.

What it means

ParquetVectorizedInputFormat's seek() only supports seeking before any rows have been read (totalCountLoadedSoFar must be 0). The reader pre-loads row groups into memory, so a re-seek after reading has started is impossible without discarding loaded state. Flink throws UnsupportedOperationException to make this contract explicit.

Source

Thrown at flink-formats/flink-parquet/src/main/java/org/apache/flink/formats/parquet/ParquetVectorizedInputFormat.java:451

            for (int i = 0; i < types.size(); ++i) {
                if (!unknownFieldsIndices.contains(i)) {
                    columnReaders[i] =
                            createColumnReader(
                                    isUtcTimestamp,
                                    projectedTypes[i],
                                    types.get(i),
                                    requestedSchema.getColumns(),
                                    pages,
                                    fields.get(i),
                                    0);
                }
            }
            totalCountLoadedSoFar += pages.getRowCount();
        }

        public void seek(long rowCount) {
            if (totalCountLoadedSoFar != 0) {
                throw new UnsupportedOperationException("Only support seek at first.");
            }

            List<BlockMetaData> blockMetaData = reader.getRowGroups();

            for (BlockMetaData metaData : blockMetaData) {
                if (metaData.getRowCount() > rowCount) {
                    break;
                } else {
                    reader.skipNextRowGroup();
                    rowsReturned += metaData.getRowCount();
                    totalCountLoadedSoFar += metaData.getRowCount();
                    rowCount -= metaData.getRowCount();
                }
            }

            this.recordsToSkip = rowCount;
        }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Create a new reader instance for each seek position instead of re-seeking an existing one
  2. Ensure seek() is the first call after construction, before any batch read
  3. If re-positioning is required, use the recordsToSkip mechanism at reader creation or the skip support in the file source splits

Example fix

// before
reader.nextBatch(); // loads a row group
reader.seek(1000);   // throws

// after
// finish or discard the reader, then:
ParquetVectorizedInputFormat.Reader<T> fresh = format.createReader(config);
fresh.seek(1000);
Defensive patterns

Strategy: validation

Validate before calling

// seek only on a fresh reader
if (!reader.isCompleted() && !anyBatchRead) { /* track first-read yourself */ }
// simplest: always seek exactly once, immediately after creating the reader

Prevention

When it happens

Trigger: Calling reader.seek(rowCount) on a ParquetVectorizedInputFormat.Reader a second time, or calling seek() after nextBatch()/readRecords() has already loaded at least one row group (totalCountLoadedSoFar != 0).

Common situations: Batch readers that reposition for a retry, checkpoint restore that re-seeks a partially consumed split, or custom split enumeration logic that seeks mid-stream instead of creating a fresh reader per split.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/50b3f0881a645b94. Report an issue: GitHub.