{"record":{"id":"ba2e331b90ba8c0f","repo":"flowable/flowable-engine","slug":"process-definition-with-id-processdefinition","errorCode":null,"errorMessage":"Process definition with id '\" + processDefinition.getId() + \" ' is already active","messagePattern":"Process definition with id '\" \\+ processDefinition\\.getId\\(\\) \\+ \" ' is already active","errorType":"http","errorClass":"FlowableConflictException","httpStatus":409,"severity":"warning","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/repository/ProcessDefinitionResource.java","lineNumber":228,"sourceCode":"                    \n                } else {\n                    formInfo = formRepositoryService.getFormModelByKey(startEvent.getFormKey(), processDefinition.getTenantId(),\n                            processEngineConfiguration.isFallbackToDefaultTenant());\n                }\n            }\n        }\n\n        if (formInfo == null) {\n            // Definition found, but no form attached\n            throw new FlowableObjectNotFoundException(\"Process definition does not have a form defined: \" + processDefinition.getId());\n        }\n        \n        return formInfo;\n    }\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);","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/repository/ProcessDefinitionResource.java#L210-L246","documentation":"activateProcessDefinition checks repositoryService.isProcessDefinitionSuspended first; if the definition is not suspended, activating it is a no-op conflict and Flowable throws FlowableConflictException (HTTP 409). This guards against redundant state transitions.","triggerScenarios":"PUT /repository/process-definitions/{id} with {\"action\":\"activate\"} on a definition that is already active.","commonSituations":"Retry logic re-sending activate after a first success; race between two administrators; scheduled activation scripts running twice.","solutions":["Check suspension state first (GET definition, suspended flag) and skip activation if already active","Catch FlowableConflictException / HTTP 409 and treat as success in idempotent automation","Use the date parameter for scheduled activation instead of repeated calls"],"exampleFix":"// before\nput(id, {\"action\":\"activate\"}); // 409 if already active\n// after\nif (def.suspended) put(id, {\"action\":\"activate\"});","handlingStrategy":"validation","validationCode":"const def = await api.getProcessDefinition(defId);\nif (!def.suspended) return { skipped: true, reason: 'already active' };","typeGuard":"const needsActivation = (def) => def != null && def.suspended === true;","tryCatchPattern":"try { await api.activateProcessDefinition(defId); }\ncatch (e) { if (e.status === 409) return { skipped: true }; throw e; }","preventionTips":["Read the suspended flag before activating or suspending","Make automation idempotent by treating 409 as success","Use scheduled activation with a date instead of polling calls"],"tags":["rest","conflict","state-management"],"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"}