apache/druid · error · RE
Expected a single column but got
Error message
Expected a single column but got [%s] columns. Please check broker logs for more information.
What it means
After confirming exactly one row, buildTaskResponse requires that row to have exactly one column containing the taskId. If the row is null or has a different column count, this RE is thrown. It protects the /sql/statements response contract: the task-status query must return a single taskId value.
Solutions
- Inspect broker logs for the internal task-status query and compare its select list to the expected single-column taskId projection.
- Ensure all cluster nodes run the same Druid version (no mixed-version schema mismatch).
- Remove any custom extensions/filters that could alter the status query, then retry the statements API call.
- If persistent, file/check Druid issue tracker for regressions in SqlStatementResource.
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
// verify the status query response shape client-side before consuming
Object[] row = rows.get(0);
if (row == null || row.length != 1) {
throw new IllegalStateException("Unexpected task-status row shape, expected single taskId column");
} Try / catch
try {
submitAsync(query);
} catch (DruidException e) {
if (e.getMessage().contains("Expected a single column")) {
upgradeOrAlignClusterVersions(); // schema mismatch between nodes
}
throw e;
} Prevention
- Do not modify internal task-status queries in custom patches without updating SqlStatementResource expectations.
- Run a homogeneous Druid version across brokers and MSQ engines.
- Test async statements API after upgrades in staging.
When it happens
Trigger: The single row returned by the internal task-status query has zero or multiple columns — e.g. a changed/incorrect internal SELECT for the ingestion task id, or an unexpected engine result schema after an upgrade or a custom query modification.
Common situations: Running a modified/patched Druid where the internal status query's projection changed; interacting with the statements API through a proxy that rewrites the request; mixed-version cluster where broker and MSQ engine disagree on the status row schema.
Related errors
- Expected a single row but got
- Failed to handle query
- Query [ ] was not found. The query details are no longer…
- The current user[ ] cannot view query id[ ] since the query…
- Unable to stream results back for query
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/6b7493967d1cb7b6.
Report an issue: GitHub.
Appendix: source
Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlStatementResource.java:530
return responseBuilder.build();
}
catch (Throwable e) {
// make sure to close yielder if anything happened before starting to serialize the response.
yielder0.close();
throw e;
}
}
private Response buildTaskResponse(Sequence<Object[]> sequence, AuthenticationResult authenticationResult)
{
List<Object[]> rows = sequence.toList();
int numRows = rows.size();
if (numRows != 1) {
throw new RE("Expected a single row but got [%d] rows. Please check broker logs for more information.", numRows);
}
Object[] firstRow = rows.get(0);
if (firstRow == null || firstRow.length != 1) {
throw new RE(
"Expected a single column but got [%s] columns. Please check broker logs for more information.",
firstRow == null ? 0 : firstRow.length
);
}
String taskId = String.valueOf(firstRow[0]);
Optional<SqlStatementResult> statementResult = getStatementStatus(
taskId,
authenticationResult,
true,
Action.READ,
false
);
if (statementResult.isPresent()) {
return Response.status(Response.Status.OK).entity(statementResult.get()).build();
} else {
return buildNonOkResponse(View on GitHub (pinned to 9b90983fd2)