apache/druid · error · RE

Expected a single row but got

Error message

Expected a single row but got [%d] rows. Please check broker logs for more information.

What it means

SqlStatementResource.buildTaskResponse materializes the task-status query sequence and requires exactly one row (the row carrying the taskId). If numRows != 1 this RE is thrown. The /sql/statements endpoint expects the underlying task status query to return a single row; any other cardinality means the engine returned an unexpected result shape.

Solutions

  1. Check broker and overlord logs for the actual task status query outcome and the MSQ task's fate.
  2. Look up the controller task id in the overlord console to see if it failed at startup; fix the underlying query error and resubmit.
  3. Retry the request if it was a transient desync between broker and overlord.
  4. Verify Druid service versions are consistent so the task-status query contract is respected.

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// before using the statements API, confirm the task exists
// GET /druid/indexer/v1/task/<controllerTaskId>/status returns 200 and non-null status

Try / catch

try {
  submitAsync(query);
} catch (DruidException e) {
  if (e.getMessage().contains("Expected a single row")) {
    checkOverlordForTaskFailure(); // task died before status row was produced
    resubmitQuery();
  } else { throw e; }
}

Prevention

When it happens

Trigger: POSTing to /druid/v2/sql/statements where the internally issued task-status query (SELECT of the ingestion task's state) yields zero rows (task not found/failed to start) or multiple rows, before extracting the taskId column.

Common situations: Querying the async statements API when the MSQ controller task died instantly and its status row is missing; broker/controller desync so the status lookup returns multiple entries; client bugs submitting duplicate/odd queries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/4e92954cd1b621c9. Report an issue: GitHub.

Appendix: source

Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/sql/resources/SqlStatementResource.java:526

      if (sqlQuery.includeHeader()) {
        responseBuilder.header(SqlResource.SQL_HEADER_RESPONSE_HEADER, SqlResource.SQL_HEADER_VALUE);
      }

      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
    );

View on GitHub (pinned to 9b90983fd2)