{"record":{"id":"726d1d91a39b62fa","repo":"prestodb/presto","slug":"pinot-unexpected-response","errorCode":"PINOT_UNEXPECTED_RESPONSE","errorMessage":"Expected row of %d columns","messagePattern":"Expected row of (.+?) columns","errorType":"error_code","errorClass":"PinotException","httpStatus":null,"severity":"error","filePath":"presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/PinotBrokerPageSource.java","lineNumber":265,"sourceCode":"            pageBuilder.declarePositions(counter);\n            Page page = pageBuilder.build();\n\n            // TODO: Implement chunking if the result set is ginormous\n            finished = true;\n\n            return page;\n        }\n        finally {\n            readTimeNanos += System.nanoTime() - start;\n        }\n    }\n\n    protected void setRows(String query, List<BlockBuilder> blockBuilders, List<Type> types, JsonNode rows)\n    {\n        for (int rowNumber = 0; rowNumber < rows.size(); ++rowNumber) {\n            JsonNode result = rows.get(rowNumber);\n            if (result == null || result.size() < blockBuilders.size()) {\n                throw new PinotException(\n                    PINOT_UNEXPECTED_RESPONSE,\n                    Optional.of(query),\n                    String.format(\"Expected row of %d columns\", blockBuilders.size()));\n            }\n            for (int columnNumber = 0; columnNumber < blockBuilders.size(); columnNumber++) {\n                setValue(types.get(columnNumber), blockBuilders.get(columnNumber), result.get(columnNumber));\n            }\n        }\n    }\n\n    protected static void handleCommonResponse(String pinotQuery, JsonNode jsonBody)\n    {\n        JsonNode numServersResponded = jsonBody.get(\"numServersResponded\");\n        JsonNode numServersQueried = jsonBody.get(\"numServersQueried\");\n\n        if (numServersQueried == null || numServersResponded == null || numServersQueried.asInt() > numServersResponded.asInt()) {\n            throw new PinotException(\n                PINOT_INSUFFICIENT_SERVER_RESPONSE,","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/PinotBrokerPageSource.java#L247-L283","documentation":"PinotBrokerPageSource.setRows throws PinotException(PINOT_UNEXPECTED_RESPONSE) when a row in the Pinot broker's JSON response (the 'rows' array of a broker query result) is missing or has fewer fields than the query's column count (blockBuilders.size()). The connector expects the response's rows to align 1:1 with the requested columns; a short or null row means the broker returned a malformed or structurally unexpected response. The query text is attached via the exception's Optional.of(query) for debugging.","triggerScenarios":"populateFromQueryResults iterates resultJson.get('Rows') and a row is null or result.size() < number of requested columns: Pinot returned an error/empty payload shaped differently than expected, a broker-side query failure produced a partial response, or the number of selected columns/aggregates changed while the response retained an older shape.","commonSituations":"Pinot broker under stress returning truncated responses; broker version incompatibility with the connector's expected JSON result format (e.g. pagination or aggregation result format change); queries mixing selection and aggregation where the connector builds column expectations differently from the server; large responses cut off by broker timeouts.","solutions":["Log/inspect the actual Pinot broker response (the failing query is in the PinotException's error message) to see the returned row shape","Run the same query directly against the Pinot broker (POST /query/sql) to confirm whether the broker itself returns short rows","Check Pinot broker health/version and network stability — retry the query; transient broker errors often produce malformed responses","Upgrade the Pinot connector and Pinot cluster together so the JSON result format expectations match","Reduce query complexity/column count or add LIMIT to rule out response-size related truncation"],"exampleFix":"// before (fragile direct query)\nSELECT * FROM pinot_table WHERE ts > 0\n// after (explicit columns, bounded result)\nSELECT id, CAST(value AS DOUBLE) FROM pinot_table WHERE ts > 0 LIMIT 1000","handlingStrategy":"retry","validationCode":"// Validate broker response shape before iterating rows\nJsonNode rows = response.get(\"Rows\");\nif (rows == null || !rows.isArray()) {\n  throw new IllegalStateException(\"Pinot broker response missing Rows array\");\n}\nfor (JsonNode row : rows) {\n  if (row == null || row.size() < expectedColumnCount) {\n    throw new IllegalStateException(\"Pinot returned short row: \" + row);\n  }\n}","typeGuard":"boolean isValidRows(JsonNode rows, int expectedColumns) {\n  return rows != null && rows.isArray()\n      && java.util.stream.StreamSupport.stream(rows.spliterator(), false)\n          .allMatch(r -> r != null && r.size() >= expectedColumns);\n}","tryCatchPattern":"try {\n  return pageSource.getNextPage();\n} catch (PinotException e) {\n  if (e.getErrorCode() == PINOT_UNEXPECTED_RESPONSE.toErrorCode()) {\n    if (attempt < MAX_RETRIES) { return retryQuery(); } // transient broker truncation\n    throw new IllegalStateException(\"Pinot broker returned malformed response for query: \" + e.getMessage());\n  }\n  throw e;\n}","preventionTips":["Retry idempotent Pinot queries once or twice — broker hiccups often produce truncated responses","Keep Pinot cluster and connector versions matched to avoid JSON result-format drift","Monitor broker error rates and GC/timeout metrics; malformed responses correlate with broker stress","Run large queries directly against the broker endpoint to validate response shape before wiring into Presto","Bound result sizes with LIMIT to reduce truncation risk on big scans"],"tags":["pinot","malformed-response","pinot-exception","broker","presto"],"backgroundTag":"unexpected-response-format","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}