apache/druid · error · BadRequestException

Requested taskId[ ] doesn't match with taskId[ ]

Error message

Requested taskId[%s] doesn't match with taskId[%s]

What it means

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.

Solutions

  1. 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
  2. Re-fetch the current taskId from the overlord/tasks API if the task was restarted and retry
  3. Verify the request is going to the correct peon port for this task, not another task on the same host
  4. Remove the header entirely if identity assurance is not needed — the check is skipped when TASK_ID_HEADER is absent

Example fix

// before
request.header("X-Druid-TASK-ID", rawTaskId); // may mismatch if URL-encoding differs
// after
request.header("X-Druid-TASK-ID", URLEncoder.encode(taskId, StandardCharsets.UTF_8));
Defensive patterns

Strategy: validation

Validate before calling

String expected = URLEncoder.encode(taskId, StandardCharsets.UTF_8);
if (requestTaskId != null
    && !requestTaskId.equals(taskId)
    && !URLDecoder.decode(requestTaskId, StandardCharsets.UTF_8).equals(taskId)) {
  throw new IllegalStateException("taskId mismatch: " + requestTaskId);
}

Type guard

boolean taskIdMatches(String headerValue, String pathTaskId) {
  return headerValue == null
      || headerValue.equals(pathTaskId)
      || URLDecoder.decode(headerValue, StandardCharsets.UTF_8).equals(pathTaskId);
}

Try / catch

try {
  Response r = client.target(chatUrl).request().header("X-Druid-TASK-ID", encodedTaskId).get();
} catch (BadRequestException e) {
  refreshTaskIdAndRetry(); // fetch current taskId from overlord
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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

Appendix: source

Thrown at server/src/main/java/org/apache/druid/segment/realtime/ChatHandlerResource.java:67

    this.handlers = handlers;
    this.taskId = taskHolder.getTaskId();
  }

  @Path("/{id}")
  public Object doTaskChat(@PathParam("id") String handlerId, @Context HttpHeaders headers)
  {
    if (taskId != null) {
      final List<String> requestTaskIds = headers.getRequestHeader(TASK_ID_HEADER);
      final String requestTaskId = requestTaskIds != null && !requestTaskIds.isEmpty()
                                   ? Iterables.getOnlyElement(requestTaskIds)
                                   : null;

      // 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)