apache/druid · warning

Controller: %s

Error message

Controller: %s

What it means

In ControllerImpl.runInternal (MSQ engine), when a query finishes with an error, the controller error report is logged as 'Controller: %s' before the error is reported to the caller. This log line is the controller-side diagnostic for why the MSQ query failed; the actual failure detail is in the rendered error report message.

Source

Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/exec/ControllerImpl.java:516

      taskStateForReport = TaskState.FAILED;

      if (cancelReason == CancellationReason.UNKNOWN && cancelException != null) {
        // Cancellation triggered by an external error. Report the original error.
        if (exceptionEncountered != null) {
          cancelException.addSuppressed(exceptionEncountered);
        }
        errorForReport =
            MSQErrorReport.fromException(queryId(), selfHost, null, cancelException, querySpec.getColumnMappings());
      } else if (cancelReason != null) {
        errorForReport = MSQErrorReport.fromFault(queryId(), selfHost, null, new CanceledFault(cancelReason));
      } else {
        errorForReport = MSQTasks.makeErrorReport(queryId(), selfHost, controllerError, workerError);
      }

      // Log the errors we encountered.
      if (controllerError != null) {
        log.warn("Controller: %s", MSQTasks.errorReportToLogMessage(controllerError, context.isDebug()));
      }

      if (workerError != null) {
        log.warn("Worker: %s", MSQTasks.errorReportToLogMessage(workerError, context.isDebug()));
      }
    }
    if (queryKernel != null && queryKernel.isSuccess()) {
      // If successful, encourage workers to exit successfully.
      // Only send this command to participating workers. For task-based queries, this is all tasks, since tasks
      // are launched only when needed. For Dart, this is any servers that were actually assigned work items.
      postFinishToWorkers(queryKernel.getAllParticipatingWorkers());
      workerManager.stop(false);
    } else {
      // If not successful, cancel running tasks.
      if (workerManager != null) {
        workerManager.stop(true);
      }
    }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Read the full rendered message after 'Controller:' — it names the MSQ fault class and root cause; fix the reported underlying issue.
  2. If the cause is a worker fault, also check the paired 'Worker:' log line and the specific task's logs.
  3. Enable query context 'debug':true to get fuller stack traces in the error report.

Example fix

// before (client)
INSERT INTO dst SELECT ... WITH context {"debug": false}
// after
INSERT INTO dst SELECT ... WITH context {"debug": true} // richer Controller/Worker diagnostics
Defensive patterns

Strategy: try-catch

Try / catch

try {
  runMsqQuery(query);
} catch (MSQException e) {
  // read fault class + message rendered after "Controller:" in controller logs
  handleMsqFault(e.getFaultClass(), e.getMessage());
}

Prevention

When it happens

Trigger: Any MSQ (SQL INSERT/REPLACE/DART) query fails during controller execution: planning faults, worker faults, task failures, or user errors (e.g. bad context values) surface through this controller error logging path.

Common situations: Users see 'Controller:' followed by a report like 'Query did not have proper context' or 'Fault class ...' in the Overlord/controller logs after a failed MSQ query in the Druid console or via JDBC.

Related errors


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