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

  1. Regenerate the ticket and request schema from the current table metadata so field count matches
  2. Update the client to build its schema from the same metadata used to create the ticket
  3. 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

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


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