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
- Read the full rendered message after 'Controller:' — it names the MSQ fault class and root cause; fix the reported underlying issue.
- If the cause is a worker fault, also check the paired 'Worker:' log line and the specific task's logs.
- 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
- Set context {"debug":true} when diagnosing MSQ failures for fuller reports.
- Read the fault class name in the Controller log line; it maps directly to remediation docs.
- Keep controller (Overlord) logs alongside task logs to correlate failures.
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.