prestodb/presto · error · PinotException

PINOT_EXCEPTION

PINOT_EXCEPTION

Error message

Query %s encountered exception %s

What it means

Thrown when the Pinot broker response contains a non-empty 'exceptions' array whose first entry does not have errorCode 180. Any broker-reported exception is surfaced as a PinotException carrying the full first exception JSON (code, message) alongside the original query.

Source

Thrown at presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/PinotBrokerPageSource.java:298

        if (numServersQueried == null || numServersResponded == null || numServersQueried.asInt() > numServersResponded.asInt()) {
            throw new PinotException(
                PINOT_INSUFFICIENT_SERVER_RESPONSE,
                Optional.of(pinotQuery),
                String.format("Only %s out of %s servers responded for query %s", numServersResponded.asInt(), numServersQueried.asInt(), pinotQuery));
        }

        JsonNode exceptions = jsonBody.get("exceptions");
        if (exceptions != null && exceptions.isArray() && exceptions.size() > 0) {
            if (exceptions.get(0).get("errorCode").asInt() == 180) {
                throw new PinotException(
                    PINOT_UNAUTHENTICATED_EXCEPTION,
                    Optional.empty(),
                    "Query authentication failed.");
            }
            // Pinot is known to return exceptions with benign errorcodes like 200
            // so we treat any exception as an error
            throw new PinotException(
                PINOT_EXCEPTION,
                Optional.of(pinotQuery),
                String.format("Query %s encountered exception %s", pinotQuery, exceptions.get(0)));
        }
    }

    protected static String asText(JsonNode node)
    {
        if (node.isArray()) {
            String[] results = new String[node.size()];
            for (int i = 0; i < node.size(); i++) {
                results[i] = asText(node.get(i));
            }
            return Arrays.toString(results);
        }
        checkState(node.isValueNode());
        return node.isNull() ? null : node.asText();
    }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Read the embedded exception JSON in the message: its 'errorCode' and 'message' name the underlying Pinot failure
  2. If it is a query timeout (errorCode 200/410 style), reduce query scope or raise Pinot broker timeout (query.timeoutMs)
  3. Validate the generated SQL/PQL against Pinot's supported syntax for your Pinot version
  4. Check Pinot broker/server logs for the query id to see the full stack trace

Example fix

null
Defensive patterns

Strategy: try-catch

Try / catch

try {
    connector.query(sql);
} catch (PinotException e) {
    if (e.getErrorCode() == PinotErrorCode.PINOT_EXCEPTION) {
        // parse the embedded exception JSON in e.getMessage() to get the
        // real Pinot errorCode/message, then branch on it
    }
    throw e;
}

Prevention

When it happens

Trigger: handleCommonResponse finds exceptions array with size > 0 and first errorCode != 180; the exact Pinot error (e.g. query timeout, bad query, segment load failure) is embedded in exceptions.get(0) in the message.

Common situations: Pinot broker query timeouts, invalid PQL/SQL rejected by Pinot, quota/broker limits hit, server-side segment errors surfaced through the broker.

Related errors


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