{"record":{"id":"f8450bebdd9fc5ba","repo":"flowable/flowable-engine","slug":"process-definition-with-id-processdefinition-f8450b","errorCode":null,"errorMessage":"Process definition with id '\" + processDefinition.getId() + \" ' is already suspended","messagePattern":"Process definition with id '\" \\+ processDefinition\\.getId\\(\\) \\+ \" ' is already suspended","errorType":"http","errorClass":"FlowableConflictException","httpStatus":409,"severity":"warning","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/repository/ProcessDefinitionResource.java","lineNumber":242,"sourceCode":"    }\n\n    protected ProcessDefinitionResponse activateProcessDefinition(ProcessDefinition processDefinition, boolean suspendInstances, Date date) {\n        if (!repositoryService.isProcessDefinitionSuspended(processDefinition.getId())) {\n            throw new FlowableConflictException(\"Process definition with id '\" + processDefinition.getId() + \" ' is already active\");\n        }\n        repositoryService.activateProcessDefinitionById(processDefinition.getId(), suspendInstances, date);\n\n        ProcessDefinitionResponse response = restResponseFactory.createProcessDefinitionResponse(processDefinition);\n\n        // No need to re-fetch the ProcessDefinition, just alter the suspended\n        // state of the result-object\n        response.setSuspended(false);\n        return response;\n    }\n\n    protected ProcessDefinitionResponse suspendProcessDefinition(ProcessDefinition processDefinition, boolean suspendInstances, Date date) {\n        if (repositoryService.isProcessDefinitionSuspended(processDefinition.getId())) {\n            throw new FlowableConflictException(\"Process definition with id '\" + processDefinition.getId() + \" ' is already suspended\");\n        }\n        repositoryService.suspendProcessDefinitionById(processDefinition.getId(), suspendInstances, date);\n\n        ProcessDefinitionResponse response = restResponseFactory.createProcessDefinitionResponse(processDefinition);\n\n        // No need to re-fetch the ProcessDefinition, just alter the suspended\n        // state of the result-object\n        response.setSuspended(true);\n        return response;\n    }\n\n}\n","sourceCodeStart":224,"sourceCodeEnd":255,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/repository/ProcessDefinitionResource.java#L224-L255","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nPOST /flowable-rest/repository/process-definitions/myDef  {\"action\":\"suspend\"}  // 409 if already suspended\n\n// after\n// GET /flowable-rest/repository/process-definitions/myDef\nif (!response.body.suspended) {\n  POST /flowable-rest/repository/process-definitions/myDef  {\"action\":\"suspend\"}\n}","handlingStrategy":"validation","validationCode":"const def = await get(`/repository/process-definitions/${id}`);\nif (def.suspended) return; // already suspended, skip action","typeGuard":"const canSuspend = (d) => typeof d?.suspended === 'boolean' && !d.suspended;","tryCatchPattern":"try { await suspendDefinition(id); } catch (e) { if (e.status === 409 || e instanceof FlowableConflictException) { /* treat as success */ } else throw e; }","preventionTips":["Read the definition's suspended flag before lifecycle actions","Treat 409 on idempotent state transitions as success","Serialize admin operations on the same definition"],"tags":["rest-api","conflict","process-definition","idempotency"],"backgroundTag":"invalid-state-transition","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}