{"record":{"id":"df3a3e6e7344e0e8","repo":"apache/druid","slug":"can-t-find-chathandler-for-handler-s","errorCode":null,"errorMessage":"Can't find chatHandler for handler[%s]","messagePattern":"Can't find chatHandler for handler\\[(.+?)\\]","errorType":"http","errorClass":"ServiceUnavailableException","httpStatus":503,"severity":"warning","filePath":"server/src/main/java/org/apache/druid/segment/realtime/ChatHandlerResource.java","lineNumber":80,"sourceCode":"      // Sanity check: Callers set TASK_ID_HEADER to our taskId (URL-encoded, if >= 0.14.0) if they want to be\n      // assured of talking to the correct task, and not just some other task running on the same port.\n      if (requestTaskId != null\n          && !requestTaskId.equals(taskId)\n          && !StringUtils.urlDecode(requestTaskId).equals(taskId)) {\n        throw new BadRequestException(\n            StringUtils.format(\"Requested taskId[%s] doesn't match with taskId[%s]\", requestTaskId, taskId)\n        );\n      }\n    }\n\n    final Optional<ChatHandler> handler = handlers.get(handlerId);\n\n    if (handler.isPresent()) {\n      return handler.get();\n    }\n\n    // Return HTTP 503 so SpecificTaskRetryPolicy retries in case the handler is not registered yet or has been registered before shutdown.\n    throw new ServiceUnavailableException(StringUtils.format(\"Can't find chatHandler for handler[%s]\", handlerId));\n  }\n}\n","sourceCodeStart":62,"sourceCodeEnd":83,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/segment/realtime/ChatHandlerResource.java#L62-L83","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Check task is running before calling its chat endpoint\nTaskStatus status = overlordClient.status(taskId).get();\nif (status.getState() != TaskState.RUNNING) throw new IllegalStateException(\"Task not running\");","typeGuard":null,"tryCatchPattern":"try {\n  return chatClient.call(handlerId);\n} catch (ServiceUnavailableException e) {\n  return RetryUtils.retry(() -> chatClient.call(handlerId), shouldRetry503, MAX_ATTEMPTS);\n}","preventionTips":["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"],"tags":["http-503","chat-handler","retry"],"backgroundTag":"resource-not-found","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}