apache/druid · warning · ServiceUnavailableException
Can't find chatHandler for handler
Error message
Can't find chatHandler for handler[%s]
What it means
doTaskChat looks up the requested ChatHandler among handlers registered on this peon. When no handler is registered for handlerId, the resource throws ServiceUnavailableException (HTTP 503) so that SpecificTaskRetryPolicy on the client side retries — the handler may not be registered yet (task still starting) or was already unregistered during shutdown.
Solutions
- Simply retry — 503 is intentional and SpecificTaskRetryPolicy will back off and retry automatically
- Verify the task is still running via the overlord task status API before calling its chat endpoints
- Check task location data is current; stale routing sends requests to the wrong peon
- If it persists, check task logs for early startup failure that prevented ChatHandler registration
Defensive patterns
Strategy: retry
Validate before calling
// Check task is running before calling its chat endpoint
TaskStatus status = overlordClient.status(taskId).get();
if (status.getState() != TaskState.RUNNING) throw new IllegalStateException("Task not running"); Try / catch
try {
return chatClient.call(handlerId);
} catch (ServiceUnavailableException e) {
return RetryUtils.retry(() -> chatClient.call(handlerId), shouldRetry503, MAX_ATTEMPTS);
} Prevention
- Rely on SpecificTaskRetryPolicy which already backs off on 503
- Avoid calling chat endpoints immediately after task submission
- Verify task location is current before sending requests
When it happens
Trigger: Calling a task's chat endpoint (e.g. a Kafka ingestion task's /handoff or status endpoint) before the task registered its ChatHandler, after the task completed and unregistered it, or when the request was routed to a peon not actually hosting that task.
Common situations: Race right after task launch when clients query status too eagerly; querying a completed/killed task; stale task-location info in overlord causing requests to the wrong host/port.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Current thread is interrupted after
- Exception while watching for role
- Failed to check missing segments due to missing responses…
- Failed to load segment
- handler already registered for service
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/df3a3e6e7344e0e8.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/segment/realtime/ChatHandlerResource.java:80
// Sanity check: Callers set TASK_ID_HEADER to our taskId (URL-encoded, if >= 0.14.0) if they want to be
// assured of talking to the correct task, and not just some other task running on the same port.
if (requestTaskId != null
&& !requestTaskId.equals(taskId)
&& !StringUtils.urlDecode(requestTaskId).equals(taskId)) {
throw new BadRequestException(
StringUtils.format("Requested taskId[%s] doesn't match with taskId[%s]", requestTaskId, taskId)
);
}
}
final Optional<ChatHandler> handler = handlers.get(handlerId);
if (handler.isPresent()) {
return handler.get();
}
// Return HTTP 503 so SpecificTaskRetryPolicy retries in case the handler is not registered yet or has been registered before shutdown.
throw new ServiceUnavailableException(StringUtils.format("Can't find chatHandler for handler[%s]", handlerId));
}
}
View on GitHub (pinned to 9b90983fd2)