{"record":{"id":"57b4452b995b2777","repo":"apache/druid","slug":"requested-taskid-s-doesn-t-match-with-taskid-s","errorCode":null,"errorMessage":"Requested taskId[%s] doesn't match with taskId[%s]","messagePattern":"Requested taskId\\[(.+?)\\] doesn't match with taskId\\[(.+?)\\]","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/main/java/org/apache/druid/segment/realtime/ChatHandlerResource.java","lineNumber":67,"sourceCode":"    this.handlers = handlers;\n    this.taskId = taskHolder.getTaskId();\n  }\n\n  @Path(\"/{id}\")\n  public Object doTaskChat(@PathParam(\"id\") String handlerId, @Context HttpHeaders headers)\n  {\n    if (taskId != null) {\n      final List<String> requestTaskIds = headers.getRequestHeader(TASK_ID_HEADER);\n      final String requestTaskId = requestTaskIds != null && !requestTaskIds.isEmpty()\n                                   ? Iterables.getOnlyElement(requestTaskIds)\n                                   : null;\n\n      // 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":49,"sourceCodeEnd":83,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/segment/realtime/ChatHandlerResource.java#L49-L83","documentation":"ChatHandlerResource.doTaskChat is the HTTP entry point that routes chat requests to locally-hosted task handlers. Callers may set the TASK_ID_HEADER to assert they are talking to the intended task; if the header's taskId does not match the taskId in the request URL (after URL-decoding), the resource rejects the request with a 400 BadRequestException.","triggerScenarios":"Sending an HTTP request to a task's chat endpoint with a X-Druid-TASK-ID header whose value differs from the taskId in the request path — e.g. stale taskId from a retried task, an unencoded or wrongly encoded taskId (tasks from before 0.14.0 are not URL-encoded), or hitting the wrong peon port hosting a different task.","commonSituations":"Client code built for Druid < 0.14.0 sending non-URL-encoded task IDs while the server expects encoded ones; custom tooling reusing an old taskId after task restart; misrouted requests when multiple tasks share a host.","solutions":["Ensure the caller sends the exact taskId of the task being targeted in the TASK_ID_HEADER, URL-encoding it for task IDs created by Druid >= 0.14.0","Re-fetch the current taskId from the overlord/tasks API if the task was restarted and retry","Verify the request is going to the correct peon port for this task, not another task on the same host","Remove the header entirely if identity assurance is not needed — the check is skipped when TASK_ID_HEADER is absent"],"exampleFix":"// before\nrequest.header(\"X-Druid-TASK-ID\", rawTaskId); // may mismatch if URL-encoding differs\n// after\nrequest.header(\"X-Druid-TASK-ID\", URLEncoder.encode(taskId, StandardCharsets.UTF_8));","handlingStrategy":"validation","validationCode":"String expected = URLEncoder.encode(taskId, StandardCharsets.UTF_8);\nif (requestTaskId != null\n    && !requestTaskId.equals(taskId)\n    && !URLDecoder.decode(requestTaskId, StandardCharsets.UTF_8).equals(taskId)) {\n  throw new IllegalStateException(\"taskId mismatch: \" + requestTaskId);\n}","typeGuard":"boolean taskIdMatches(String headerValue, String pathTaskId) {\n  return headerValue == null\n      || headerValue.equals(pathTaskId)\n      || URLDecoder.decode(headerValue, StandardCharsets.UTF_8).equals(pathTaskId);\n}","tryCatchPattern":"try {\n  Response r = client.target(chatUrl).request().header(\"X-Druid-TASK-ID\", encodedTaskId).get();\n} catch (BadRequestException e) {\n  refreshTaskIdAndRetry(); // fetch current taskId from overlord\n}","preventionTips":["Always URL-encode the taskId header for tasks created by Druid >= 0.14.0","Re-fetch taskId from the overlord after any task restart","Confirm the request targets the correct peon port for that task"],"tags":["http","chat-handler","task-id"],"backgroundTag":"invalid-identifier","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"}