flowable/flowable-engine · warning · FlowableConflictException
Process definition with id '" + processDefinition.getId() +…
Error message
Process definition with id '" + processDefinition.getId() + " ' is already suspended
What it means
Flowable REST throws FlowableConflictException (HTTP 409) when you attempt to suspend a process definition that is already in suspended state. The REST layer checks repositoryService.isProcessDefinitionSuspended() before applying the action, so the state change would be a no-op conflict. This prevents clients from blindly toggling suspension and losing track of actual definition state.
Solutions
- Check suspension state first via GET /repository/process-definitions/{id} and only send the suspend action if suspended is false.
- Catch FlowableConflictException / handle HTTP 409 on the client and treat it as success when the desired end state (suspended) is already reached.
- Use the matching 'activate' action instead if the intent was to resume the definition.
- Serialize admin operations (locking or auditing) so two actors do not issue conflicting lifecycle actions for the same definition.
Example fix
// before
POST /flowable-rest/repository/process-definitions/myDef {"action":"suspend"} // 409 if already suspended
// after
// GET /flowable-rest/repository/process-definitions/myDef
if (!response.body.suspended) {
POST /flowable-rest/repository/process-definitions/myDef {"action":"suspend"}
} Defensive patterns
Strategy: validation
Validate before calling
const def = await get(`/repository/process-definitions/${id}`);
if (def.suspended) return; // already suspended, skip action Type guard
const canSuspend = (d) => typeof d?.suspended === 'boolean' && !d.suspended;
Try / catch
try { await suspendDefinition(id); } catch (e) { if (e.status === 409 || e instanceof FlowableConflictException) { /* treat as success */ } else throw e; } Prevention
- Read the definition's suspended flag before lifecycle actions
- Treat 409 on idempotent state transitions as success
- Serialize admin operations on the same definition
When it happens
Trigger: POST /repository/process-definitions/{processDefinitionId} with body {"action":"suspend"} (optionally with suspendProcessInstances/date) when the definition was already suspended by a previous call or by another user/job.
Common situations: Double-submitting a suspend action from an admin UI; a prior suspend with suspendProcessInstances=true already suspended the definition; retry logic re-sending a request that actually succeeded; concurrent admins acting on the same definition.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- A group with id '' already exists.
- Engine property already exists
- Process instance with id
- Process instance with id
- User '' is already part of group ''.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/f8450bebdd9fc5ba.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/repository/ProcessDefinitionResource.java:242
}
protected ProcessDefinitionResponse activateProcessDefinition(ProcessDefinition processDefinition, boolean suspendInstances, Date date) {
if (!repositoryService.isProcessDefinitionSuspended(processDefinition.getId())) {
throw new FlowableConflictException("Process definition with id '" + processDefinition.getId() + " ' is already active");
}
repositoryService.activateProcessDefinitionById(processDefinition.getId(), suspendInstances, date);
ProcessDefinitionResponse response = restResponseFactory.createProcessDefinitionResponse(processDefinition);
// No need to re-fetch the ProcessDefinition, just alter the suspended
// state of the result-object
response.setSuspended(false);
return response;
}
protected ProcessDefinitionResponse suspendProcessDefinition(ProcessDefinition processDefinition, boolean suspendInstances, Date date) {
if (repositoryService.isProcessDefinitionSuspended(processDefinition.getId())) {
throw new FlowableConflictException("Process definition with id '" + processDefinition.getId() + " ' is already suspended");
}
repositoryService.suspendProcessDefinitionById(processDefinition.getId(), suspendInstances, date);
ProcessDefinitionResponse response = restResponseFactory.createProcessDefinitionResponse(processDefinition);
// No need to re-fetch the ProcessDefinition, just alter the suspended
// state of the result-object
response.setSuspended(true);
return response;
}
}
View on GitHub (pinned to d6d39ce1c6)