{"record":{"id":"2a4d9dd0e503d584","repo":"conductor-oss/conductor","slug":"cannot-archive-task-of-workflow-with-non-t","errorCode":null,"errorMessage":"Cannot archive task: {} of workflow: {} with non-terminal status: {}","messagePattern":"Cannot archive task: (.+?) of workflow: (.+?) with non-terminal status: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/com/netflix/conductor/core/dal/ExecutionDAOFacade.java","lineNumber":618,"sourceCode":"        if (archiveTask) {\n            if (task.getStatus().isTerminal()) {\n                // Only allow archival if task is in terminal state\n                // DO NOT archive async, since if archival errors out, task data will be lost\n                indexDAO.updateTask(\n                        workflow.getWorkflowId(),\n                        task.getTaskId(),\n                        new String[] {ARCHIVED_FIELD},\n                        new Object[] {true});\n            } else if (task.getStatus() == TaskModel.Status.SCHEDULED) {\n                // SCHEDULED tasks may not have been canceled yet (e.g. if cancelNonTerminalTasks\n                // failed for this task). Skip archival to allow the rest of the workflow removal\n                // to proceed rather than blocking on a task that was never started.\n                LOGGER.warn(\n                        \"Skipping archival of task: {} of workflow: {} with SCHEDULED status\",\n                        task.getTaskId(),\n                        workflow.getWorkflowId());\n            } else {\n                throw new IllegalArgumentException(\n                        \"Cannot archive task: \"\n                                + task.getTaskId()\n                                + \" of workflow: \"\n                                + workflow.getWorkflowId()\n                                + \" with non-terminal status: \"\n                                + task.getStatus());\n            }\n        } else {\n            // Not archiving, remove task from index\n            indexDAO.asyncRemoveTask(workflow.getWorkflowId(), task.getTaskId());\n        }\n    }\n\n    public void extendLease(TaskModel taskModel) {\n        taskModel.setUpdateTime(System.currentTimeMillis());\n        executionDAO.updateTask(taskModel);\n    }\n","sourceCodeStart":600,"sourceCodeEnd":636,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/core/src/main/java/com/netflix/conductor/core/dal/ExecutionDAOFacade.java#L600-L636","documentation":"Thrown by removeTaskIndex when archiveTask=true but the task status is non-terminal AND not SCHEDULED. SCHEDULED tasks are explicitly skipped (logged) because they may not have been canceled yet; every other non-terminal status (IN_PROGRESS, etc.) raises this IllegalArgumentException. Archiving a non-terminal task would persist an in-flight task as its final state.","triggerScenarios":"Calling workflow removal with archival on a workflow that contains a task still IN_PROGRESS (or any non-terminal, non-SCHEDULED status). The guard is the final else after checking terminal status and the SCHEDULED special case.","commonSituations":"A workflow is being archived while one of its tasks is still actively executing (e.g. an async/system task that has not completed). A stuck task that never reached terminal status. Archival invoked during an in-flight cancellation that has not propagated to all tasks.","solutions":["Ensure all tasks reach a terminal status before archiving the workflow (the cancelNonTerminalTasks step normally handles this).","If a task is genuinely stuck, terminate it or force the workflow to a terminal state before removal.","If archival is not required, remove with archiveWorkflow=false so tasks are deleted from the index rather than archived.","Investigate why cancelNonTerminalTasks did not bring the offending task to terminal status."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure task is terminal (or SCHEDULED) before archiving\nTaskModel.Status s = task.getStatus();\nif (!s.isTerminal() && s != TaskModel.Status.SCHEDULED) {\n    throw new IllegalArgumentException(\n        \"Cannot archive task \" + task.getTaskId()\n            + \" with non-terminal status \" + s);\n}","typeGuard":null,"tryCatchPattern":"try {\n    facade.removeWorkflow(id, true);\n} catch (IllegalArgumentException e) {\n    // a task is non-terminal and not SCHEDULED -> cancel/terminate tasks first\n}","preventionTips":["Run cancelNonTerminalTasks to completion before archiving a workflow.","If a task cannot reach terminal status, terminate the workflow rather than archiving.","Use archive=false when preservation of in-flight tasks is not required."],"tags":["task","archival","state-machine","illegal-argument"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}