{"record":{"id":"8e5df94c455dd5cb","repo":"apache/druid","slug":"worker-d-cannot-transistion-from-state-s-to-st","errorCode":null,"errorMessage":"Worker[%d] cannot transistion from state[%s] to state[%s] while sending work order","messagePattern":"Worker\\[(.+?)\\] cannot transistion from state\\[(.+?)\\] to state\\[(.+?)\\] while sending work order","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"multi-stage-query/src/main/java/org/apache/druid/msq/kernel/controller/ControllerStageTracker.java","lineNumber":295,"sourceCode":"    }\n    return workers;\n  }\n\n  /**\n   * Indicates that the work order for worker has been sent. Transitions the state to {@link ControllerWorkerStagePhase#READING_INPUT}\n   * if no more work orders need to be sent.\n   *\n   * @param worker\n   */\n  void workOrderSentForWorker(int worker)\n  {\n\n    workerToPhase.compute(worker, (wk, state) -> {\n      if (state == null) {\n        throw new ISE(\"Worker[%d] not found for stage[%s]\", wk, stageDef.getStageNumber());\n      }\n      if (!ControllerWorkerStagePhase.READING_INPUT.canTransitionFrom(state)) {\n        throw new ISE(\n            \"Worker[%d] cannot transistion from state[%s] to state[%s] while sending work order\",\n            worker,\n            state,\n            ControllerWorkerStagePhase.READING_INPUT\n        );\n      }\n      return ControllerWorkerStagePhase.READING_INPUT;\n    });\n    if (phase != ControllerStagePhase.READING_INPUT) {\n      if (allWorkOrdersSent()) {\n        // if no more work orders need to be sent, change state to reading input from retrying.\n        transitionTo(ControllerStagePhase.READING_INPUT);\n      }\n    }\n\n  }\n\n  /**","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/multi-stage-query/src/main/java/org/apache/druid/msq/kernel/controller/ControllerStageTracker.java#L277-L313","documentation":"Thrown when workOrderSentForWorker is called for a worker whose current phase cannot legally transition to READING_INPUT. The worker state machine forbids re-sending a work order once the worker has advanced past a phase from which READING_INPUT is reachable, indicating out-of-order or duplicated work-order handling in the controller.","triggerScenarios":"Calling workOrderSentForWorker twice for the same worker, or after the worker already progressed to POST_SHUFFLE / finished phases, so ControllerWorkerStagePhase.READING_INPUT.canTransitionFrom(state) returns false.","commonSituations":"Duplicate work-order send due to controller retries; race between task-status callbacks and work-order issuance; test harnesses invoking controller methods out of order.","solutions":["Only send the work order once per worker and per stage; track which workers already received one.","Check the worker's current phase before sending and skip if it has already advanced past READING_INPUT.","Add idempotency/ordering to the code path that triggers workOrderSentForWorker (e.g. dedupe on task id)."],"exampleFix":"// before\ntracker.workOrderSentForWorker(worker); // may be called twice\n// after\nif (!workOrdersSent.contains(worker)) {\n  tracker.workOrderSentForWorker(worker);\n  workOrdersSent.add(worker);\n}","handlingStrategy":"validation","validationCode":"if (sentWorkOrders.add(stageAndWorkerKey)) {\n  tracker.workOrderSentForWorker(worker);\n}","typeGuard":null,"tryCatchPattern":"try {\n  tracker.workOrderSentForWorker(worker);\n} catch (IllegalStateException e) {\n  // worker already past READING_INPUT; safe to skip duplicate\n}","preventionTips":["Send each work order exactly once per worker/stage (dedupe set).","Avoid interleaving task-status processing with work-order issuance."],"tags":["druid","msq","state-machine","worker-phase"],"backgroundTag":"invalid-state-transition","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"}