{"record":{"id":"8df6124b8784d756","repo":"flowable/flowable-engine","slug":"provided-decision-must-have-a-deployment-id","errorCode":null,"errorMessage":"Provided decision must have a deployment id.","messagePattern":"Provided decision must have a deployment id\\.","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/deployer/DmnDeploymentHelper.java","lineNumber":108,"sourceCode":"        DecisionEntity existingDecision;\n\n        if (tenantId != null && !tenantId.equals(DmnEngineConfiguration.NO_TENANT_ID)) {\n            existingDecision = decisionTableEntityManager.findLatestDecisionByKeyAndTenantId(key, tenantId);\n        } else {\n            existingDecision = decisionTableEntityManager.findLatestDecisionByKey(key);\n        }\n\n        return existingDecision;\n    }\n\n    /**\n     * Gets the persisted version of the already-deployed decision. Note that this is different from {@link #getMostRecentVersionOfDecision} as it looks specifically for a decision\n     * that is already persisted and attached to a particular deployment, rather than the latest version across all deployments.\n     */\n    public DecisionEntity getPersistedInstanceOfDecision(DecisionEntity decision) {\n        String deploymentId = decision.getDeploymentId();\n        if (StringUtils.isEmpty(decision.getDeploymentId())) {\n            throw new FlowableIllegalArgumentException(\"Provided decision must have a deployment id.\");\n        }\n\n        DecisionEntityManager decisionEntityManager = CommandContextUtil.getDmnEngineConfiguration().getDecisionEntityManager();\n        DecisionEntity persistedDecision;\n        if (decision.getTenantId() == null || DmnEngineConfiguration.NO_TENANT_ID.equals(decision.getTenantId())) {\n            persistedDecision = decisionEntityManager.findDecisionByDeploymentAndKey(deploymentId, decision.getKey());\n        } else {\n            persistedDecision = decisionEntityManager.findDecisionByDeploymentAndKeyAndTenantId(deploymentId, decision.getKey(), decision.getTenantId());\n        }\n\n        return persistedDecision;\n    }\n\n    /**\n     * Creates new diagrams for decisions if the deployment is new, the decision in question supports it, and the engine is configured to make new diagrams.\n     *\n     * When this method creates a new diagram, it also persists it via the ResourceEntityManager and adds it to the resources of the deployment.\n     */","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/deployer/DmnDeploymentHelper.java#L90-L126","documentation":"DmnDeploymentHelper.getPersistedInstanceOfDecision requires the incoming DecisionEntity to already carry a deploymentId, since it queries for the decision persisted under that specific deployment. An empty deploymentId triggers FlowableIllegalArgumentException before any entity-manager query runs.","triggerScenarios":"Calling getPersistedInstanceOfDecision with a freshly built (not yet persisted) DecisionEntity whose deploymentId was never set — e.g. custom deployer code that constructs a decision instead of obtaining it from the deployment pipeline.","commonSituations":"Custom DmnDeployer implementations that reorder/replace the built-in deployers so the decision's deploymentId field isn't populated yet; unit tests building DecisionEntity objects manually; refactors that drop the setDeploymentId call.","solutions":["Set deploymentId on the decision before calling this method (decision.setDeploymentId(deployment.getId())).","Ensure the built-in DeploymentIdDeployer/DmnDeployment stages run so the entity is populated during deployment.","In tests, populate deploymentId (and key) on the fixture before invoking the helper.","Use getMostRecentVersionOfDecision instead if you want version lookup by key, not per-deployment lookup."],"exampleFix":"// before\nDecisionEntity persisted = deploymentHelper.getPersistedInstanceOfDecision(newDecision);\n// after\nnewDecision.setDeploymentId(deploymentEntity.getId());\nDecisionEntity persisted = deploymentHelper.getPersistedInstanceOfDecision(newDecision);","handlingStrategy":"validation","validationCode":"if (StringUtils.isEmpty(decision.getDeploymentId())) {\n    throw new IllegalArgumentException(\"decision.deploymentId must be set before per-deployment lookup\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    DecisionEntity persisted = helper.getPersistedInstanceOfDecision(decision);\n} catch (FlowableIllegalArgumentException e) {\n    // decision was not yet attached to a deployment\n}","preventionTips":["Only call this helper from within the deployment pipeline after deploymentId is set","Don't construct DecisionEntity fixtures without deploymentId in tests","Keep built-in deployer ordering intact"],"tags":["flowable","dmn","deployer","null-argument","validation"],"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-14T11:17:12.474Z"}