floci-io/floci · warning · AwsException
PipelineExecutionNotStoppableException
PipelineExecutionNotStoppableException
Error message
Pipeline execution is already in a terminal state
What it means
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.
Source
Thrown at src/main/java/io/github/hectorvent/floci/services/codepipeline/CodePipelineService.java:293
execution.setVariables(variableList(request.path("variables")));
Map<String, String> trigger = new LinkedHashMap<>();
trigger.put("triggerType", "StartPipelineExecution");
trigger.put("triggerDetail", "manual");
if (clientToken != null) {
trigger.put("clientRequestToken", clientToken);
}
execution.setTrigger(trigger);
putExecution(execution);
applyExecutionMode(execution);
executor.submit(() -> runExecution(pipeline, execution));
return mapper.createObjectNode().put("pipelineExecutionId", execution.getPipelineExecutionId());
}
private ObjectNode stopPipelineExecution(JsonNode request, String region, String account) {
CodePipelineExecution execution = requireExecution(
account, region, text(request, "pipelineName"), text(request, "pipelineExecutionId"));
if (isTerminal(execution.getStatus())) {
throw new AwsException("PipelineExecutionNotStoppableException",
"Pipeline execution is already in a terminal state", 400);
}
execution.setStopRequested(true);
execution.setAbandon(request.path("abandon").asBoolean(false));
execution.setStatus("Stopping");
execution.setStatusSummary(request.path("reason").asText("Stop requested."));
execution.setLastUpdateTime(now());
if (execution.isAbandon()) {
execution.getActionExecutions().stream()
.filter(a -> "InProgress".equals(a.getStatus()))
.forEach(a -> {
a.setStatus("Abandoned");
a.setLastUpdateTime(now());
});
}
putExecution(execution);
return mapper.createObjectNode().put("pipelineExecutionId", execution.getPipelineExecutionId());
}View on GitHub (pinned to 62ff490619)
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.
Example fix
// before
client.stop_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id) # may already be terminal
// after
status = client.get_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id) \
['pipelineExecution']['status']
if status in ('InProgress', 'Stopping'):
client.stop_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id) Defensive patterns
Strategy: try-catch
Validate before calling
status = client.get_pipeline_execution(
pipelineName='p', pipelineExecutionId=exec_id)['pipelineExecution']['status']
if status in ('InProgress', 'Stopping'):
client.stop_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id) Try / catch
try:
client.stop_pipeline_execution(pipelineName='p', pipelineExecutionId=exec_id)
except ClientError as e:
if e.response['Error']['Code'] == 'PipelineExecutionNotStoppableException':
logger.info('execution already finished; nothing to stop')
else:
raise Prevention
- 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.
When it happens
Trigger: StopPipelineExecution(pipelineName, pipelineExecutionId) called after the execution finished; dashboards/monitors racing the pipeline's natural completion; retrying a stop that succeeded earlier.
Common situations: 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.
Related errors
- TLS enabled but no certificate provided and self-signed gene
- ValidationException
- ValidationException
- PipelineNameInUseException
- ActionTypeAlreadyExistsException
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/dca848393ffbc742.
Report an issue: GitHub.