{"record":{"id":"973c818701502de3","repo":"flowable/flowable-engine","slug":"provided-process-definition-must-have-a-deployment","errorCode":null,"errorMessage":"Provided process definition must have a deployment id.","messagePattern":"Provided process definition must have a deployment id\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/deployer/BpmnDeploymentHelper.java","lineNumber":158,"sourceCode":"        ProcessDefinitionEntity existingDefinition = null;\n\n        if (tenantId != null && !tenantId.equals(ProcessEngineConfiguration.NO_TENANT_ID)) {\n            existingDefinition = processDefinitionManager.findLatestDerivedProcessDefinitionByKeyAndTenantId(key, tenantId);\n        } else {\n            existingDefinition = processDefinitionManager.findLatestDerivedProcessDefinitionByKey(key);\n        }\n\n        return existingDefinition;\n    }\n\n    /**\n     * Gets the persisted version of the already-deployed process definition. Note that this is different from {@link #getMostRecentVersionOfProcessDefinition} as it looks specifically for a process\n     * definition that is already persisted and attached to a particular deployment, rather than the latest version across all deployments.\n     */\n    public ProcessDefinitionEntity getPersistedInstanceOfProcessDefinition(ProcessDefinitionEntity processDefinition) {\n        String deploymentId = processDefinition.getDeploymentId();\n        if (StringUtils.isEmpty(processDefinition.getDeploymentId())) {\n            throw new IllegalStateException(\"Provided process definition must have a deployment id.\");\n        }\n\n        ProcessDefinitionEntityManager processDefinitionManager = CommandContextUtil.getProcessEngineConfiguration().getProcessDefinitionEntityManager();\n        ProcessDefinitionEntity persistedProcessDefinition = null;\n        if (processDefinition.getTenantId() == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(processDefinition.getTenantId())) {\n            persistedProcessDefinition = processDefinitionManager.findProcessDefinitionByDeploymentAndKey(deploymentId, processDefinition.getKey());\n        } else {\n            persistedProcessDefinition = processDefinitionManager.findProcessDefinitionByDeploymentAndKeyAndTenantId(deploymentId, processDefinition.getKey(), processDefinition.getTenantId());\n        }\n\n        return persistedProcessDefinition;\n    }\n\n    /**\n     * Updates all timers and events for the process definition. The undeploy half iterates the previous\n     * process definition's top-level start events; each behavior either does its own per-start-event work\n     * (e.g. the EventRegistry \"manual\" re-point) or registers an obsolete event subscription / timer job\n     * handler type with the context. After the undeploy iteration the deployer issues one mass-delete per","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/deployer/BpmnDeploymentHelper.java#L140-L176","documentation":"getPersistedInstanceOfProcessDefinition requires the given process definition entity to already be attached to a deployment, because it looks the definition up by deploymentId + key. If deploymentId is null or empty it fails fast with this IllegalStateException rather than issuing a meaningless query.","triggerScenarios":"Calling BpmnDeploymentHelper.getPersistedInstanceOfProcessDefinition with a ProcessDefinitionEntity that has not yet been persisted/assigned a deploymentId — e.g. during deployment before the entity is saved, or a programmatically built definition.","commonSituations":"Custom deployers or extension code invoking the helper with an in-memory (unsaved) definition; calling it in the wrong deployment lifecycle phase; mixing up getMostRecentVersionOfProcessDefinition with getPersistedInstanceOfProcessDefinition.","solutions":["Only call this method after the definition has been persisted and its deploymentId set","If you need the latest definition regardless of deployment, use getMostRecentVersionOfProcessDefinition instead","Persist the deployment (or let the standard Persister/Deployer pipeline run) before invoking this helper","Guard custom code with a null/empty deploymentId check and skip or reroute accordingly"],"exampleFix":"// before\nhelper.getPersistedInstanceOfProcessDefinition(unsavedDefinition);\n\n// after\nif (StringUtils.isNotEmpty(unsavedDefinition.getDeploymentId())) {\n    helper.getPersistedInstanceOfProcessDefinition(unsavedDefinition);\n} else {\n    helper.getMostRecentVersionOfProcessDefinition(unsavedDefinition);\n}","handlingStrategy":"validation","validationCode":"if (processDefinition.getDeploymentId() == null || processDefinition.getDeploymentId().isEmpty()) {\n    // use latest-version lookup instead\n    return bpmnDeploymentHelper.getMostRecentVersionOfProcessDefinition(processDefinition);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only call getPersistedInstanceOfProcessDefinition with definitions already persisted","Prefer getMostRecentVersionOfProcessDefinition when deployment linkage is unknown","Keep custom deployer code inside the standard lifecycle phases"],"tags":["deployment","process-definition","precondition","lifecycle"],"backgroundTag":"missing-required-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}