flowable/flowable-engine · error · FlowableObjectNotFoundException
No decision found for key
Error message
No decision found for key <decisionKey>. There was also no fall back decision found for default tenant <defaultTenant>.
What it means
Thrown when a decision is resolved by key and tenantId, fallback-to-default-tenant is enabled, the default tenant resolves to a non-empty value, but findLatestDecisionByKeyAndTenantId still finds no Decision for that default tenant. The engine treats this as a hard not-found because even the fallback could not locate the decision.
Solutions
- Check what DefaultTenantProvider returns and confirm decisions are actually deployed under that tenant; deploy the .dmn resource with that tenantId if not.
- Fix or replace the defaultTenantProvider so it returns the tenant that owns the decision.
- Verify the decision key is correct via DmnRepositoryService decision query.
- Disable fallbackToDefaultTenant if the decision should only resolve by the explicitly given tenantId.
Example fix
// before
dmnEngineConfiguration.setDefaultTenantProvider((tenantId, scope, key) -> "missing-tenant");
// after
dmnEngineConfiguration.setDefaultTenantProvider((tenantId, scope, key) ->
dmnRepositoryService.createDecisionQuery().decisionKey(key).list().isEmpty() ? null : tenantId != null ? tenantId : "default"); Defensive patterns
Strategy: validation
Validate before calling
String defaultTenant = defaultTenantProvider.getDefaultTenant(tenantId, ScopeTypes.DMN, key);
if (defaultTenant != null && dmnRepositoryService.createDecisionQuery().decisionKey(key).tenantId(defaultTenant).count() == 0) {
log.error("Decision {} not deployed under default tenant {}", key, defaultTenant);
} Try / catch
try { dmnEngine.executeDecision(builder.decisionKey(key).tenantId(tenant)); }
catch (FlowableObjectNotFoundException e) { throw new IllegalStateException("Decision " + key + " missing even under default tenant", e); } Prevention
- Ensure DMN models are deployed under the tenant your DefaultTenantProvider resolves
- Unit-test the DefaultTenantProvider configuration
- Keep fallback tenant deployments in sync with per-tenant deployments
When it happens
Trigger: Executing a decision with decisionKey and tenantId where (isFallbackToDefaultTenant || config fallback) is true, DefaultTenantProvider returns a non-empty default tenant, and no Decision row exists for key+defaultTenant.
Common situations: Decision never deployed under the default tenant; default tenant provider misconfigured to a tenant that has no DMN deployments; decision deployed only to a custom tenant while the fallback resolves to the default one.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Could not find deployment with id
- No decision found for key
- No decision found for key
- No decision found for key
- No decision found for key
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/bb4339b2e7120ee5.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/cmd/AbstractExecuteDecisionCmd.java:148
// If there is no decision table found linked to the deployment id, try to find one without a specific deployment id.
decision = decisionEntityManager.findLatestDecisionByKey(decisionKey);
if (decision == null) {
throw new FlowableObjectNotFoundException("No decision found for key: " + decisionKey +
" and parent deployment id " + parentDeploymentId +
". There was also no fall back decision found without parent deployment id.");
}
}
} else if (StringUtils.isNotEmpty(decisionKey) && StringUtils.isNotEmpty(tenantId)) {
decision = decisionEntityManager.findLatestDecisionByKeyAndTenantId(decisionKey, tenantId);
if (decision == null) {
if (executeDecisionContext.isFallbackToDefaultTenant() || dmnEngineConfiguration.isFallbackToDefaultTenant()) {
String defaultTenant = dmnEngineConfiguration.getDefaultTenantProvider().getDefaultTenant(tenantId, ScopeTypes.DMN, decisionKey);
if (StringUtils.isNotEmpty(defaultTenant)) {
decision = decisionEntityManager.findLatestDecisionByKeyAndTenantId(decisionKey, defaultTenant);
if (decision == null) {
throw new FlowableObjectNotFoundException("No decision found for key: " + decisionKey +
". There was also no fall back decision found for default tenant " +
defaultTenant + ".");
}
} else {
decision = decisionEntityManager.findLatestDecisionByKey(decisionKey);
if (decision == null) {
throw new FlowableObjectNotFoundException("No decision found for key: " + decisionKey +
". There was also no fall back decision found without tenant.");
}
}
} else {
throw new FlowableObjectNotFoundException(
"No decision found for key: " + decisionKey + " and tenantId: " + tenantId + ".");
}
}
View on GitHub (pinned to d6d39ce1c6)