{"record":{"id":"53397ed08567f38a","repo":"apache/druid","slug":"cannot-mark-the-stage-s-finished","errorCode":null,"errorMessage":"Cannot mark the stage: [%s] finished","messagePattern":"Cannot mark the stage: \\[(.+?)\\] finished","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"multi-stage-query/src/main/java/org/apache/druid/msq/kernel/controller/ControllerQueryKernel.java","lineNumber":612,"sourceCode":"      if (stageTracker.getPhase() != ControllerStagePhase.NEW) {\n        throw new ISE(\"Cannot start the stage: [%s]\", stageId);\n      }\n\n      stageTracker.start();\n    });\n  }\n\n  /**\n   * Checks if the stage can be finished, delegates call to {@link ControllerStageTracker#finish()} for internal phase\n   * transition and registers the transition in this query kernel\n   * <p>\n   * If the method is called with strict = true, we confirm if the stage can be marked as finished or else\n   * throw illegal argument exception\n   */\n  public void finishStage(final StageId stageId, final boolean strict)\n  {\n    if (strict && !effectivelyFinishedStages.contains(stageId)) {\n      throw new IAE(\"Cannot mark the stage: [%s] finished\", stageId);\n    }\n    doWithStageTracker(stageId, stageTracker -> {\n      stageTracker.finish();\n      effectivelyFinishedStages.remove(stageId);\n    });\n    stageWorkOrders.remove(stageId);\n  }\n\n  /**\n   * Delegates call to {@link ControllerStageTracker#getWorkerInputs()}\n   */\n  public WorkerInputs getWorkerInputsForStage(final StageId stageId)\n  {\n    return getStageTrackerOrThrow(stageId).getWorkerInputs();\n  }\n\n  /**\n   * Delegates call to {@link ControllerStageTracker#addPartialKeyInformationForWorker(int, PartialKeyStatisticsInformation)}.","sourceCodeStart":594,"sourceCodeEnd":630,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/multi-stage-query/src/main/java/org/apache/druid/msq/kernel/controller/ControllerQueryKernel.java#L594-L630","documentation":"Thrown by ControllerQueryKernel.finishStage(stageId, strict=true) as an IllegalArgumentException when the stage is not in the effectivelyFinishedStages set, i.e. it has not been pre-marked as effectively finished, so strictly finishing it would violate the state machine.","triggerScenarios":"Calling finishStage(stageId, true) for a stage whose completion was never registered via markEffectivelyFinishedToKernel (the effectivelyFinishedStages set does not contain the stage). Typically from markSuccessfulTerminalStagesAsFinished when the controller believes a terminal stage succeeded but the kernel never recorded it.","commonSituations":"Controller/state-machine logic marking terminal stages finished out of order; stages skipped due to earlier failures so they never become effectively finished; desync between the controller's ChatHandler/state machine and the kernel after a restart.","solutions":["Verify the stage reached an effectively-finished state before calling finishStage with strict=true","Pass strict=false if best-effort finishing is acceptable and the stage may legitimately not be effectively finished","Inspect the state-machine step that registers effectively-finished stages (StagePhase equivalents) and confirm it ran for this stage","If this follows a controller restart, check that kernel transitions were fully persisted before replaying terminal-stage finishing"],"exampleFix":"// before\nkernel.finishStage(stageId, true);\n\n// after\nif (kernel.isStageEffectivelyFinished(stageId)) {\n  kernel.finishStage(stageId, true);\n} else {\n  kernel.finishStage(stageId, false);\n}","handlingStrategy":"validation","validationCode":"if (!queryKernel.isStageEffectivelyFinished(stageId)) {\n  queryKernel.finishStage(stageId, false);\n} else {\n  queryKernel.finishStage(stageId, true);\n}","typeGuard":null,"tryCatchPattern":"try {\n  queryKernel.finishStage(stageId, true);\n} catch (IllegalArgumentException e) {\n  LOG.warn(e, \"Stage %s not effectively finished; finishing non-strictly\", stageId);\n  queryKernel.finishStage(stageId, false);\n}","preventionTips":["Register stages as effectively finished before strict finishing","Use strict=false unless the caller is certain of the stage's completion state","Keep markSuccessfulTerminalStagesAsFinished ordering consistent with kernel state","Persist effectively-finished transitions so restart replay stays in sync"],"tags":["msq","state-machine","controller"],"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-14T05:17:10.506Z"}