flowable/flowable-engine · error · FlowableIllegalArgumentException
tenantId is null
Error message
tenantId is null
What it means
FlowableIllegalArgumentException thrown by DmnHistoricDecisionExecutionQuery.tenantId(String) when a null tenant identifier is passed. Tenant id is used to filter historic decision executions in multi-tenant deployments; the library rejects null eagerly so the query never runs with an unintended 'match all tenants' semantics.
Source
Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/HistoricDecisionExecutionQueryImpl.java:171
@Override
public DmnHistoricDecisionExecutionQuery caseInstanceIdWithChildren(String caseInstanceId) {
this.caseInstanceIdWithChildren = caseInstanceId;
return this;
}
@Override
public DmnHistoricDecisionExecutionQuery failed(Boolean failed) {
if (failed == null) {
throw new FlowableIllegalArgumentException("failed is null");
}
this.failed = failed;
return this;
}
@Override
public DmnHistoricDecisionExecutionQuery tenantId(String tenantId) {
if (tenantId == null) {
throw new FlowableIllegalArgumentException("tenantId is null");
}
this.tenantId = tenantId;
return this;
}
@Override
public DmnHistoricDecisionExecutionQuery tenantIdLike(String tenantIdLike) {
if (tenantIdLike == null) {
throw new FlowableIllegalArgumentException("tenantId is null");
}
this.tenantIdLike = tenantIdLike;
return this;
}
@Override
public DmnHistoricDecisionExecutionQuery withoutTenantId() {
this.withoutTenantId = true;
return this;View on GitHub (pinned to d6d39ce1c6)
Solutions
- Pass the actual non-null tenant id string the executions were created with.
- If tenant filtering is not needed, omit the tenantId() call.
- For pattern matching use tenantIdLike(pattern) with a non-null string, or null-check the resolved tenant before querying.
Example fix
// before
query.tenantId(tenantContext.getTenantId()); // getTenantId() may return null
// after
String tenantId = tenantContext.getTenantId();
if (tenantId != null) {
query.tenantId(tenantId);
} Defensive patterns
Strategy: validation
Validate before calling
String tenantId = tenantContext.getTenantId();
if (tenantId == null || tenantId.isEmpty()) {
throw new IllegalStateException("No tenant resolved for query");
}
query.tenantId(tenantId); Type guard
boolean hasTenant(Object v) { return v instanceof String s && !s.isEmpty(); } Try / catch
try {
query.tenantId(tenantId);
} catch (FlowableIllegalArgumentException e) {
throw new IllegalStateException("Tenant resolution failed before query", e);
} Prevention
- Resolve and validate the tenant id before building any query.
- Use tenantIdLike() with a default pattern if tenant is optional.
- Fail early at tenant-resolution time rather than at query-build time.
When it happens
Trigger: Calling .tenantId(null) on a DmnHistoricDecisionExecutionQuery — usually when the tenant id is taken from an unset context, an absent authentication/session attribute, or a null field in the calling code.
Common situations: Multi-tenant apps where tenant resolution failed and returned null instead of a default tenant; copying query-building code where tenantId was optional; unit tests passing null placeholders.
Related errors
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/24037fb6f5141faa.
Report an issue: GitHub.