{"record":{"id":"74cf222ccb8e3486","repo":"kestra-io/kestra","slug":"execution-must-be-terminated-or-paused-and-not-kil","errorCode":null,"errorMessage":"Execution must be terminated or paused and not killed to be restarted, current state is '{execution.getState().getCurrent()}' !","messagePattern":"Execution must be terminated or paused and not killed to be restarted, current state is '(.+?)' !","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/kestra/core/services/ExecutionService.java","lineNumber":283,"sourceCode":"        if (createCommand.variables() != null) {\n            newExecution = newExecution.withVariables(createCommand.variables());\n        }\n\n        /*\n         * if (emitEvent) {\n         * eventPublisher.publishEvent(CrudEvent.create(newExecution));\n         * }\n         */\n        return newExecution;\n    }\n\n    public Execution restart(final Execution execution, Flow flow, @Nullable Integer revision) throws Exception {\n        return restart(execution, flow, revision, false);\n    }\n\n    public Execution restart(final Execution execution, Flow flow, @Nullable Integer revision, boolean emitEvent) throws Exception {\n        if (!execution.getState().canBeRestarted()) {\n            throw new IllegalStateException(\n                \"Execution must be terminated or paused and not killed to be restarted, \" +\n                    \"current state is '\" + execution.getState().getCurrent() + \"' !\"\n            );\n        }\n\n        final String newExecutionId = revision != null ? IdUtils.create() : null;\n\n        // When an execution has no task runs (e.g., failed due to concurrency limit exceeded\n        // before any task ran), restart it as a fresh child execution with an empty task-run list.\n        if (ListUtils.isEmpty(execution.getTaskRunList())) {\n            List<Label> newLabels = new ArrayList<>(ListUtils.emptyOnNull(execution.getLabels()));\n            if (!newLabels.contains(new Label(Label.RESTARTED, \"true\"))) {\n                newLabels.add(new Label(Label.RESTARTED, \"true\"));\n            }\n            Execution newExecution = execution\n                .childExecution(newExecutionId, Collections.emptyList(), execution.withState(State.Type.RESTARTED).getState())\n                .withMetadata(execution.getMetadata().nextAttempt())\n                .withLabels(newLabels);","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/kestra-io/kestra/blob/823fada9274c4f9c251ea0a516460a4f7d958032/core/src/main/java/io/kestra/core/services/ExecutionService.java#L265-L301","documentation":"The `ExecutionService.restart()` method checks `execution.getState().canBeRestarted()` before proceeding. Only executions in a terminal state (SUCCESS, FAILED, WARNING, etc.) or PAUSED state — and not KILLED — can be restarted. If the execution is still RUNNING, CREATED, QUEUED, or has been KILLED, an `IllegalStateException` is thrown. Restarting re-runs the execution from a specific task.","triggerScenarios":"Calling `POST /executions/{id}/restart` on an execution that is currently RUNNING. Restarting an execution that was KILLED (killed executions cannot be restarted). Restarting an execution that is in a non-terminal, non-paused state like CREATED or QUEUED.","commonSituations":"A user attempts to restart an execution that is still in progress. A flow was killed by the user or system and the user tries to restart it. The execution state changed between the UI display and the API call.","solutions":["Wait for the execution to reach a terminal state (SUCCESS, FAILED, WARNING) before restarting.","Killed executions cannot be restarted — trigger a new execution instead.","Refresh the execution status in the UI before clicking Restart.","For PAUSED executions, restart is allowed but should be used intentionally (it resumes from the restart point)."],"exampleFix":"# before: restart a running execution\nPOST /api/v1/executions/{runningExecutionId}/restart\n# after: wait for terminal state first\n# 1. Check execution state\nGET /api/v1/executions/{executionId}\n# 2. Only restart when state is FAILED, SUCCESS, WARNING, or PAUSED\nPOST /api/v1/executions/{executionId}/restart","handlingStrategy":"validation","validationCode":"// Check restartability before calling restart\nExecution execution = executionRepository.findById(tenantId, executionId)\n    .orElseThrow(() -> new NoSuchElementException(\"Execution not found\"));\nif (!execution.getState().canBeRestarted()) {\n    throw new IllegalStateException(\n        \"Cannot restart execution in state \" + execution.getState().getCurrent()\n            + \". Must be terminated or paused, and not killed.\");\n}\nExecution restarted = executionService.restart(execution, flow, revision);","typeGuard":"const TERMINAL_STATES: Set<string> = new Set(['SUCCESS', 'FAILED', 'WARNING', 'PAUSED', 'CANCELLED']);\n\nfunction canBeRestarted(state: string): boolean {\n    return TERMINAL_STATES.has(state) && state !== 'KILLED';\n}","tryCatchPattern":"try {\n    Execution restarted = executionService.restart(execution, flow, revision);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"must be terminated or paused\")) {\n        log.warn(\"Cannot restart execution {} in state {}: {}\",\n            execution.getId(), execution.getState().getCurrent(), e.getMessage());\n        // suggest: wait for terminal state, or trigger a new execution if killed\n        throw e;\n    }\n    throw e;\n}","preventionTips":["Verify the execution is in a terminal or paused state before calling restart.","Killed executions cannot be restarted — trigger a new execution instead.","Refresh execution status in the UI before clicking Restart.","Document that RUNNING, CREATED, and QUEUED executions cannot be restarted."],"tags":["execution","restart","state-machine","validation"],"backgroundTag":null,"analyzedSha":"823fada9274c4f9c251ea0a516460a4f7d958032","analyzedAt":"2026-08-14T06:15:17.947Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}