prestodb/presto · error · PinotException

PINOT_EXCEPTION

PINOT_EXCEPTION

Error message

Expected pinot to contain %d columns but got %d: %s

What it means

The connector validates that the DataTable returned by Pinot has exactly as many columns as the column handles the split's generated SQL expected. A mismatch means the server returned a schema different from what the generated segment query asked for, so the connector throws PINOT_EXCEPTION with both counts and the actual schema.

Source

Thrown at presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/PinotSegmentPageSource.java:112

        this.columnTypes = columnHandles.stream()
                .map(PinotSegmentPageSource::getTypeForBlock)
                .collect(Collectors.toList());
        this.pinotStreamingQueryClient = requireNonNull(pinotStreamingQueryClient, "pinotStreamingQueryClient is null");
    }

    public static void checkExceptions(DataTable dataTable, PinotSplit split, boolean markDataFetchExceptionsAsRetriable)
    {
        List<String> exceptions = dataTable.getExceptions().values().stream().toList();
        if (!exceptions.isEmpty()) {
            throw new PinotException(
                markDataFetchExceptionsAsRetriable ? PINOT_DATA_FETCH_EXCEPTION : PINOT_EXCEPTION,
                split.getSegmentPinotQuery(),
                String.format("Encountered %d pinot exceptions for split %s: %s", exceptions.size(), split, exceptions));
        }
        int numColumnsExpected = split.getExpectedColumnHandles().size();
        int numColumnsActual = dataTable.getDataSchema().size();
        if (numColumnsActual != numColumnsExpected) {
            throw new PinotException(
                    PINOT_EXCEPTION,
                    split.getSegmentPinotQuery(),
                    String.format("Expected pinot to contain %d columns but got %d: %s", numColumnsExpected, numColumnsActual, dataTable.getDataSchema()));
        }
    }

    @Override
    public long getCompletedBytes()
    {
        return completedBytes;
    }

    @Override
    public long getReadTimeNanos()
    {
        return readTimeNanos;
    }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Compare the actual DataSchema in the message against expected handles to spot the missing/extra column
  2. Sync the Pinot table schema: reload segments or refresh metadata so all segments match the Presto connector's view
  3. Check for Pinot broker/server version mismatches and align cluster versions
  4. Re-run DESCRIBE / refresh Presto metadata cache for the table, then retry
Defensive patterns

Strategy: validation

Validate before calling

// refresh metadata and verify schema consistency before querying
// DESCRIBE table; ensure columns exist in Pinot and all segments are refreshed

Try / catch

catch (PinotException e) {
    if (String.valueOf(e.getMessage()).startsWith("Expected pinot to contain")) {
        // compare expected vs actual schema in message; resync Pinot schema/metadata
    }
}

Prevention

When it happens

Trigger: checkExceptions compares split.getExpectedColumnHandles().size() with dataTable.getDataSchema().size() and they differ — e.g. Pinot dropped, added, or renamed output columns relative to the generated SQL.

Common situations: Pinot version skew changing result schema behavior; queries hitting dynamic/schema-evolution mismatches where a column exists in Presto's metadata but not in all segments; broker rewriting the query.

Related errors


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