{"record":{"id":"dca848393ffbc742","repo":"floci-io/floci","slug":"pipelineexecutionnotstoppableexception","errorCode":"PipelineExecutionNotStoppableException","errorMessage":"Pipeline execution is already in a terminal state","messagePattern":"Pipeline execution is already in a terminal state","errorType":"exception","errorClass":"AwsException","httpStatus":400,"severity":"warning","filePath":"src/main/java/io/github/hectorvent/floci/services/codepipeline/CodePipelineService.java","lineNumber":293,"sourceCode":"        execution.setVariables(variableList(request.path(\"variables\")));\n        Map<String, String> trigger = new LinkedHashMap<>();\n        trigger.put(\"triggerType\", \"StartPipelineExecution\");\n        trigger.put(\"triggerDetail\", \"manual\");\n        if (clientToken != null) {\n            trigger.put(\"clientRequestToken\", clientToken);\n        }\n        execution.setTrigger(trigger);\n        putExecution(execution);\n        applyExecutionMode(execution);\n        executor.submit(() -> runExecution(pipeline, execution));\n        return mapper.createObjectNode().put(\"pipelineExecutionId\", execution.getPipelineExecutionId());\n    }\n\n    private ObjectNode stopPipelineExecution(JsonNode request, String region, String account) {\n        CodePipelineExecution execution = requireExecution(\n                account, region, text(request, \"pipelineName\"), text(request, \"pipelineExecutionId\"));\n        if (isTerminal(execution.getStatus())) {\n            throw new AwsException(\"PipelineExecutionNotStoppableException\",\n                    \"Pipeline execution is already in a terminal state\", 400);\n        }\n        execution.setStopRequested(true);\n        execution.setAbandon(request.path(\"abandon\").asBoolean(false));\n        execution.setStatus(\"Stopping\");\n        execution.setStatusSummary(request.path(\"reason\").asText(\"Stop requested.\"));\n        execution.setLastUpdateTime(now());\n        if (execution.isAbandon()) {\n            execution.getActionExecutions().stream()\n                    .filter(a -> \"InProgress\".equals(a.getStatus()))\n                    .forEach(a -> {\n                        a.setStatus(\"Abandoned\");\n                        a.setLastUpdateTime(now());\n                    });\n        }\n        putExecution(execution);\n        return mapper.createObjectNode().put(\"pipelineExecutionId\", execution.getPipelineExecutionId());\n    }","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/codepipeline/CodePipelineService.java#L275-L311","documentation":"Thrown by stopPipelineExecution (CodePipelineService.java:293) when StopPipelineExecution targets an execution whose status is already terminal (isTerminal check — Succeeded/Failed/Cancelled and similar). Once terminal, an execution can no longer transition to Stopping, matching AWS PipelineExecutionNotStoppableException.","triggerScenarios":"StopPipelineExecution(pipelineName, pipelineExecutionId) called after the execution finished; dashboards/monitors racing the pipeline's natural completion; retrying a stop that succeeded earlier.","commonSituations":"An operator UI polling executions where the run completes between refresh and click; automation retry loops that re-send stop on failure of a prior (already-resolved) request; double-invocation of a deploy-cancel webhook.","solutions":["Re-fetch the execution status (ListPipelineExecutions/GetPipelineExecution) immediately before stopping and skip if terminal.","Treat this error as benign in retry logic — catch by code PipelineExecutionNotStoppableException and exit cleanly.","Reduce the check-to-stop window by issuing the stop from the same process that observes InProgress."],"exampleFix":"// before\nclient.stop_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id)  # may already be terminal\n\n// after\nstatus = client.get_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id) \\\n    ['pipelineExecution']['status']\nif status in ('InProgress', 'Stopping'):\n    client.stop_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id)","handlingStrategy":"try-catch","validationCode":"status = client.get_pipeline_execution(\n    pipelineName='p', pipelineExecutionId=exec_id)['pipelineExecution']['status']\nif status in ('InProgress', 'Stopping'):\n    client.stop_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id)","typeGuard":null,"tryCatchPattern":"try:\n    client.stop_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id)\nexcept ClientError as e:\n    if e.response['Error']['Code'] == 'PipelineExecutionNotStoppableException':\n        logger.info('execution already finished; nothing to stop')\n    else:\n        raise","preventionTips":["Treat NotStoppable as an expected terminal race, not a failure — catch and continue.","Refresh execution status right before issuing stops in operator tooling.","Debounce cancel webhooks so the same stop is not sent twice."],"tags":["codepipeline","lifecycle","race-condition","stop","validation"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}