prestodb/presto · error · IllegalArgumentException
Request has different number of fields than column handles:
Error message
Request has different number of fields than column handles: %d != %d
What it means
FlightShimProducer.runGetStreamAsync builds Arrow field metadata from the request and compares its size against the connector's column handles before creating the page source. If the request's field count differs from the number of column handles, it throws IllegalArgumentException, because results could not be aligned to the requested schema.
Source
Thrown at presto-flight-shim/src/main/java/com/facebook/presto/flightshim/FlightShimProducer.java:171
.setTimeZoneKey(DEFAULT_TIME_ZONE_KEY)
.setLocale(ENGLISH).build();
ConnectorId connectorId = new ConnectorId(request.getConnectorId());
Split split = new Split(connectorId, transactionHandle, connectorSplit);
List<ColumnHandle> columnHandles = request.getColumnHandlesBytes().stream().map(
columnHandleBytes -> connectorCodecs.getCodecColumnHandle().fromJson(columnHandleBytes)
).collect(toImmutableList());
AtomicInteger fieldCount = new AtomicInteger();
List<ColumnMetadata> columnsMetadata = request.getFields().stream()
.map(field -> ColumnMetadata.builder()
.setName(field.getName().orElse(format("$col%s$", fieldCount.incrementAndGet())))
.setType(field.getType().orElseThrow(() -> new IllegalArgumentException("Field type not present")))
.build())
.collect(toImmutableList());
if (columnHandles.size() != columnsMetadata.size()) {
throw new IllegalArgumentException(format("Request has different number of fields than column handles: %d != %d", columnsMetadata.size(), columnHandles.size()));
}
ConnectorPageSource connectorPageSource = pageSourceManager.createPageSource(session, split, tableHandle, columnHandles, new RuntimeStats());
try (ArrowBatchSource batchSource = new ArrowBatchSource(allocator, columnsMetadata, connectorPageSource, config.getMaxRowsPerBatch())) {
listener.setUseZeroCopy(true);
listener.start(batchSource.getVectorSchemaRoot());
columnCount = batchSource.getVectorSchemaRoot().getFieldVectors().size();
while (batchSource.nextBatch()) {
BackpressureStrategy.WaitResult waitResult;
while ((waitResult = backpressureStrategy.waitForListener(CLIENT_POLL_TIME)) == BackpressureStrategy.WaitResult.TIMEOUT) {
log.debug(format("Waiting for client to read from connector %s", request.getConnectorId()));
}
if (waitResult != BackpressureStrategy.WaitResult.READY) {
log.info(format("Read stopped from connector %s due to client wait result: %s", request.getConnectorId(), waitResult));
break;
}
rowCount += batchSource.getVectorSchemaRoot().getRowCount();View on GitHub (pinned to 55bb57d202)
Solutions
- Regenerate the ticket and request schema from the current table metadata so field count matches
- Update the client to build its schema from the same metadata used to create the ticket
- Re-fetch the table schema after any DDL change before issuing the stream request
Example fix
// before (client) // schema built from stale 3-column metadata, ticket has 4 column handles // after Schema schema = fetchCurrentSchema(ticket); // derive fields from same metadata as ticket
Defensive patterns
Strategy: validation
Validate before calling
// Client-side: assert schema size matches ticket metadata before GetStream
Schema schema = /* fields from current metadata */;
if (schema.getFields().size() != ticketColumnHandleCount) {
throw new IllegalStateException("Stale ticket/schema; refetch metadata");
} Try / catch
try (FlightStream stream = reader) { ... }
catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Request has different number of fields")) {
ticket = regenerateTicket(currentMetadata); // refresh and retry once
} else throw e;
} Prevention
- Always build the request schema and ticket from the same metadata snapshot
- Refetch table metadata after DDL changes before streaming
- Fail fast client-side on schema/hash mismatch with the ticket
When it happens
Trigger: A Flight client issues a GetStream/Ticket request whose schema (fields) has a different number of columns than the table/column handles resolved server-side for that ticket.
Common situations: Client cached an old schema after the server-side table definition changed; client built the ticket from a different SELECT list than the request schema; concurrent ALTER TABLE between ticket creation and stream request.
Related errors
- currentFieldIndexToWrite is not valid
- Unsupported FieldVector type: {fieldVector.getClass()}
- Unsupported vector type: {vector.getClass()}
- Type must be a DecimalType for DecimalVector
- Expected TimestampType but got {type.getClass().getName()}
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/25e5342359905558.
Report an issue: GitHub.