{"record":{"id":"0b054c8f29522691","repo":"conductor-oss/conductor","slug":"workflow-is-in-terminal-state-status-s","errorCode":null,"errorMessage":"Workflow is in terminal state. Status = %s","messagePattern":"Workflow is in terminal state\\. Status = (.+?)","errorType":"exception","errorClass":"ConflictException","httpStatus":409,"severity":"error","filePath":"core/src/main/java/com/netflix/conductor/core/execution/WorkflowExecutorOps.java","lineNumber":144,"sourceCode":"        this.activeWorkerLastPollMs = properties.getActiveWorkerLastPollTimeout().toMillis();\n        this.workflowStatusListener = workflowStatusListener;\n        this.taskStatusListener = taskStatusListener;\n        this.executionLockService = executionLockService;\n        this.parametersUtils = parametersUtils;\n        this.idGenerator = idGenerator;\n        this.systemTaskRegistry = systemTaskRegistry;\n        this.workflowMessageQueueDAO = workflowMessageQueueDAO;\n    }\n\n    /**\n     * @param workflowId the id of the workflow for which task callbacks are to be reset\n     * @throws ConflictException if the workflow is in terminal state\n     */\n    @Override\n    public void resetCallbacksForWorkflow(String workflowId) {\n        WorkflowModel workflow = executionDAOFacade.getWorkflowModel(workflowId, true);\n        if (workflow.getStatus().isTerminal()) {\n            throw new ConflictException(\n                    \"Workflow is in terminal state. Status = %s\", workflow.getStatus());\n        }\n\n        // Get SIMPLE tasks in SCHEDULED state that have callbackAfterSeconds > 0 and\n        // set the\n        // callbackAfterSeconds to 0\n        workflow.getTasks().stream()\n                .filter(\n                        task ->\n                                !systemTaskRegistry.isSystemTask(task.getTaskType())\n                                        && SCHEDULED == task.getStatus()\n                                        && task.getCallbackAfterSeconds() > 0)\n                .forEach(\n                        task -> {\n                            if (queueDAO.resetOffsetTime(\n                                    QueueUtils.getQueueName(task), task.getTaskId())) {\n                                task.setCallbackAfterSeconds(0);\n                                executionDAOFacade.updateTask(task);","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/core/src/main/java/com/netflix/conductor/core/execution/WorkflowExecutorOps.java#L126-L162","documentation":"resetCallbacksForWorkflow loads the workflow and refuses to operate if its status is already terminal (COMPLETED, FAILED, TIMED_OUT, TERMINATED, ROLLED_BACK), throwing a ConflictException. Resetting callbacks on a finished workflow is a no-op-at-best and is rejected to avoid inconsistent state.","triggerScenarios":"Calling the reset-callbacks API (or WorkflowExecutor.resetCallbacksForWorkflow) on a workflow that has already reached a terminal status.","commonSituations":"Retrying a reset after the workflow finished in the meantime; automation that polls and resets without checking status; UI button enabled on a completed workflow.","solutions":["Check workflow.getStatus().isTerminal() before calling resetCallbacksForWorkflow.","If the workflow is terminal and you need to re-run, use restart or rerun instead of reset.","Make the calling automation idempotent and skip already-terminal workflows."],"exampleFix":"// before\nworkflowExecutor.resetCallbacksForWorkflow(workflowId);\n\n// after\nWorkflowModel wf = executionDAOFacade.getWorkflowModel(workflowId, true);\nif (!wf.getStatus().isTerminal()) {\n    workflowExecutor.resetCallbacksForWorkflow(workflowId);\n}","handlingStrategy":"validation","validationCode":"WorkflowModel wf = executionDAOFacade.getWorkflowModel(workflowId, true);\nif (wf.getStatus().isTerminal()) {\n    // skip reset; surface to caller or use restart/rerun\n    return;\n}\nworkflowExecutor.resetCallbacksForWorkflow(workflowId);","typeGuard":null,"tryCatchPattern":"try {\n    workflowExecutor.resetCallbacksForWorkflow(workflowId);\n} catch (ConflictException e) {\n    // workflow already terminal; use restart/rerun instead\n}","preventionTips":["Check isTerminal() before calling resetCallbacksForWorkflow.","Use restart or rerun to re-run a finished workflow.","Make reset automation idempotent and skip terminal workflows."],"tags":["conductor","workflow","lifecycle","conflict","terminal-state","reset-callbacks"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}