{"record":{"id":"003b1f507b1d763b","repo":"flowable/flowable-engine","slug":"process-instance-with-id-processinstanceid-is-003b1f","errorCode":null,"errorMessage":"Process instance with id '${processInstanceId}' is already suspended.","messagePattern":"Process instance with id '(.+?)' is already suspended\\.","errorType":"exception","errorClass":"FlowableConflictException","httpStatus":409,"severity":"warning","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceResource.java","lineNumber":335,"sourceCode":"        }\n    }\n\n    protected ProcessInstanceResponse activateProcessInstance(ProcessInstance processInstance) {\n        if (!processInstance.isSuspended()) {\n            throw new FlowableConflictException(\"Process instance with id '\" + processInstance.getId() + \"' is already active.\");\n        }\n        runtimeService.activateProcessInstanceById(processInstance.getId());\n\n        ProcessInstanceResponse response = restResponseFactory.createProcessInstanceResponse(processInstance);\n\n        // No need to re-fetch the instance, just alter the suspended state of the result-object\n        response.setSuspended(false);\n        return response;\n    }\n\n    protected ProcessInstanceResponse suspendProcessInstance(ProcessInstance processInstance) {\n        if (processInstance.isSuspended()) {\n            throw new FlowableConflictException(\"Process instance with id '\" + processInstance.getId() + \"' is already suspended.\");\n        }\n        runtimeService.suspendProcessInstanceById(processInstance.getId());\n\n        ProcessInstanceResponse response = restResponseFactory.createProcessInstanceResponse(processInstance);\n\n        // No need to re-fetch the instance, just alter the suspended state of the result-object\n        response.setSuspended(true);\n        return response;\n    }\n}\n","sourceCodeStart":317,"sourceCodeEnd":346,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceResource.java#L317-L346","documentation":"Flowable REST throws FlowableConflictException when suspending a process instance that is already suspended. The suspend action on PUT of the process instance rejects the redundant state change with a 409-class conflict.","triggerScenarios":"PUT /runtime/process-instances/{id} with {\"action\":\"suspend\"} while processInstance.isSuspended() is true; two clients suspending concurrently.","commonSituations":"Maintenance-window job re-runs and re-suspends; retry after timeout duplicates the suspend call; blanket suspension script run twice.","solutions":["Verify suspended==false via GET before sending action=suspend.","Handle HTTP 409 as an idempotent success in scripts/jobs.","Track suspension state in the orchestrator to avoid duplicate calls."],"exampleFix":"// before\nput(pid, {\"action\":\"suspend\"}); // 409 on second run\n// after\nconst inst = get(pid); if (!inst.suspended) put(pid, {\"action\":\"suspend\"});","handlingStrategy":"try-catch","validationCode":"const inst = await get(`/runtime/process-instances/${pid}`); if (!inst.suspended) await put(pid, {action:'suspend'});","typeGuard":null,"tryCatchPattern":"try { put(pid, {action:'suspend'}); } catch (e) { if (e.status === 409) return; throw e; }","preventionTips":["Check suspended state before suspend","Treat 409 as idempotent success","Guard maintenance scripts against re-runs"],"tags":["rest-api","conflict","state-transition"],"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"}