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
- Create a new reader instance for each seek position instead of re-seeking an existing one
- Ensure seek() is the first call after construction, before any batch read
- 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
- Create one reader per split/seek position; never reuse readers across seeks
- Call seek() immediately after createReader, before any nextBatch/readRecords
- Wrap reader lifecycle so cancellation closes it instead of re-seeking
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
- Only support seek at first.
- Seek to many rows.
- A stream against this file was already created.
- Please use AvroParquetReaders.forSpecificRecord(Class<T>) fo
- Protocol buffer class or descriptor not specified. Please us
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/50b3f0881a645b94.
Report an issue: GitHub.