flowable/flowable-engine · error · FlowableIllegalArgumentException
decision tenantId is null
Error message
decision tenantId is null
What it means
DmnDecisionQuery.decisionTenantId(String) throws FlowableIllegalArgumentException("decision tenantId is null") when the tenantId argument is null. Multi-tenant filtering requires a concrete tenant identifier to compare against the TENANT_ID_ column; null is considered invalid input rather than 'match all'.
Source
Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/DecisionQueryImpl.java:245
protected void checkVersion(Integer version) {
if (version == null) {
throw new FlowableIllegalArgumentException("version is null");
} else if (version <= 0) {
throw new FlowableIllegalArgumentException("version must be positive");
}
}
@Override
public DecisionQueryImpl latestVersion() {
this.latest = true;
return this;
}
@Override
public DmnDecisionQuery decisionTenantId(String tenantId) {
if (tenantId == null) {
throw new FlowableIllegalArgumentException("decision tenantId is null");
}
this.tenantId = tenantId;
return this;
}
@Override
public DmnDecisionQuery decisionTenantIdLike(String tenantIdLike) {
if (tenantIdLike == null) {
throw new FlowableIllegalArgumentException("decision tenantId is null");
}
this.tenantIdLike = tenantIdLike;
return this;
}
@Override
public DmnDecisionQuery decisionWithoutTenantId() {
this.withoutTenantId = true;
return this;View on GitHub (pinned to d6d39ce1c6)
Solutions
- Guard the call: only apply decisionTenantId when the tenant id is non-null; otherwise run a tenant-agnostic query.
- Resolve the tenant from the correct source (security context/request header) and fail fast with a clear message if absent.
- If you intended a pattern match, use decisionTenantIdLike with a non-null pattern.
Example fix
// before
query.decisionTenantId(tenantContext.getTenantId()); // may be null
// after
String tenantId = tenantContext.getTenantId();
if (tenantId != null) {
query.decisionTenantId(tenantId);
} Defensive patterns
Strategy: validation
Validate before calling
String tenantId = tenantContext.getTenantId();
if (tenantId == null || tenantId.isEmpty()) {
throw new IllegalStateException("no tenant in context; cannot run tenant-scoped query");
}
query.decisionTenantId(tenantId); Type guard
boolean hasTenant(String t) { return t != null && !t.isEmpty(); } Try / catch
try {
query.decisionTenantId(tenantId);
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("tenantId")) {
// fall back to tenant-agnostic query
} else { throw e; }
} Prevention
- Ensure tenant propagation (header/security context) is configured before querying
- Guard all tenant-scoped calls behind a tenant-presence check
- In single-tenant deployments, omit tenant filters rather than passing null
When it happens
Trigger: Calling decisionTenantId(null) — usually the tenant id comes from a security context, request header, or config that is unavailable (anonymous requests, missing tenant provider, standalone engine setup without tenant support configured).
Common situations: Applications adding multi-tenancy later where some code paths have no TenantContext; tests running outside the tenant resolver; misconfigured tenant propagation (header name mismatch) leaving the variable null.
Related errors
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/ae815bc6f7c61bf0.
Report an issue: GitHub.