flowable/flowable-engine · error · IllegalArgumentException
no decision provided
Error message
no decision provided
What it means
java.lang.IllegalArgumentException thrown by RuleEngineExecutorImpl.execute(Decision, ExecuteDecisionContext) when the Decision argument is null. The rule engine executor cannot evaluate anything without a decision model, so it fails fast before attempting to resolve the decision table.
Solutions
- Ensure the DMN decision is deployed: verify the .dmn.xml resource is included in the deployment and check dmnRepositoryService.createDeployment().deploy().
- Resolve the Decision with dmnRepositoryService.getDecisionById(...) or a query and null-check the result before executing.
- Verify the decision key/id spelling and that the correct tenant is being used in multi-tenant setups.
Example fix
// before
Decision decision = dmnRepositoryService.getDecisionById(decisionId);
ruleEngineExecutor.execute(decision, context);
// after
Decision decision = dmnRepositoryService.getDecisionById(decisionId);
if (decision == null) {
throw new IllegalStateException("Decision not deployed: " + decisionId);
}
ruleEngineExecutor.execute(decision, context); Defensive patterns
Strategy: validation
Validate before calling
Decision decision = dmnRepositoryService.getDecisionById(decisionId);
if (decision == null) {
throw new IllegalStateException("Decision not found: " + decisionId);
}
ruleEngineExecutor.execute(decision, executeDecisionInfo); Type guard
boolean isExecutableDecision(Decision d) { return d != null && d.getExpression() instanceof DecisionTable; } Try / catch
try {
ruleEngineExecutor.execute(decision, ctx);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("no decision")) {
throw new IllegalStateException("Decision was not resolved/deployed before execution", e);
}
throw e;
} Prevention
- Always null-check results of decision lookups before executing.
- Verify DMN deployments and decision keys at startup in integration tests.
- In multi-tenant setups, resolve decisions with the correct tenant scoping.
When it happens
Trigger: Calling ruleEngineExecutor.execute(null, context) directly, or indirectly when a decision lookup by key/id (e.g. via DmnRepositoryService) returned null and the result was passed on without checking.
Common situations: Deployment mismatch: querying for a decision by key in a tenant where it was never deployed, so getDecisionById/getDecision returns null; typo in decision key; decision not deployed yet when an async job fires.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- activityId is null
- decision tenantId is null
- decisionDefinitionId is null
- decisionKey is null
- deploymentId is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/f5eeee4cb75a722a.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/RuleEngineExecutorImpl.java:78
ObjectMapper objectMapper, DmnEngineConfiguration dmnEngineConfiguration) {
this.hitPolicyBehaviors = hitPolicyBehaviors;
this.expressionManager = expressionManager;
this.objectMapper = objectMapper;
this.dmnEngineConfiguration = dmnEngineConfiguration;
}
/**
* Executes the given decision and creates the outcome results
*
* @param decision the DMN decision
* @param executeDecisionInfo
* @return updated execution variables map
*/
@Override
public DecisionExecutionAuditContainer execute(Decision decision, ExecuteDecisionContext executeDecisionInfo) {
if (decision == null) {
throw new IllegalArgumentException("no decision provided");
}
if (decision.getExpression() == null || !(decision.getExpression() instanceof DecisionTable currentDecisionTable)) {
throw new IllegalArgumentException("no decision table present in decision");
}
// create execution context and audit trail
ELExecutionContext executionContext = ELExecutionContextBuilder.build(decision, executeDecisionInfo);
try {
sanityCheckDecisionTable(currentDecisionTable);
// evaluate decision table
evaluateDecisionTable(currentDecisionTable, executionContext);
} catch (FlowableException fe) {
LOGGER.error("decision table execution sanity check failed", fe);
executionContext.getAuditContainer().setFailedWithException(fe);View on GitHub (pinned to d6d39ce1c6)