flowable/flowable-engine · error · FlowableIllegalArgumentException
Model tenant id is null
Error message
Model tenant id is null
What it means
ModelQueryImpl.modelTenantId() filters models by an exact tenant id, which must be a non-null String. A null tenant id cannot form a valid tenant filter, so the library throws FlowableIllegalArgumentException immediately. Multi-tenant Flowable deployments require an explicit tenant value here — empty string is allowed but null is not.
Solutions
- Resolve the tenant id before querying and fail earlier with a clear message if it is missing.
- Guard the call: if (tenantId != null) query.modelTenantId(tenantId);
- Ensure background/scheduled code runs inside a properly initialized tenant context.
- If querying across tenants is intended, omit modelTenantId() entirely instead of passing null.
Example fix
// before
ModelQuery query = repositoryService.createModelQuery()
.modelTenantId(tenantContext.getTenantId()); // null in background job
// after
String tenantId = tenantContext.getTenantId();
ModelQuery query = repositoryService.createModelQuery();
if (tenantId != null) {
query.modelTenantId(tenantId);
} else {
throw new IllegalStateException("No tenant context for model query");
} Defensive patterns
Strategy: validation
Validate before calling
if (tenantId == null || tenantId.isEmpty()) {
throw new IllegalStateException("Tenant context missing; cannot query models by tenant");
}
Model model = repositoryService.createModelQuery().modelTenantId(tenantId).singleResult(); Type guard
boolean hasTenantId(String tenantId) {
return tenantId != null && !tenantId.trim().isEmpty();
} Try / catch
try {
return repositoryService.createModelQuery().modelTenantId(tenantId).list();
} catch (FlowableIllegalArgumentException e) {
log.error("Tenant id was null when querying models: {}", e.getMessage());
throw new MissingTenantContextException();
} Prevention
- Initialize the tenant context for every thread, including scheduled jobs and async executors.
- Make tenant id a required request header/parameter validated at the API edge.
- Omit the tenant filter deliberately when cross-tenant queries are intended.
- Fail fast on missing tenant config at application startup.
When it happens
Trigger: Calling ModelQuery.modelTenantId(null), typically when the tenant id comes from an unset configuration property, a request header that was absent, or a tenant context holder that was never populated for the current thread.
Common situations: Multi-tenant applications where the tenant resolver returns null for unauthenticated/background threads (scheduled jobs, async executors); Spring config property not set; tenant header missing in an incoming REST request.
Related errors
- activity tenant id is null
- after time is null
- category is null
- categoryLike is null
- categoryLike is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/a4f56fed21a3bbe3.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/ModelQueryImpl.java:167
throw new FlowableIllegalArgumentException("Invalid usage: cannot use deployed() and notDeployed() in the same query");
}
this.notDeployed = true;
return this;
}
@Override
public ModelQuery deployed() {
if (notDeployed) {
throw new FlowableIllegalArgumentException("Invalid usage: cannot use deployed() and notDeployed() in the same query");
}
this.deployed = true;
return this;
}
@Override
public ModelQuery modelTenantId(String tenantId) {
if (tenantId == null) {
throw new FlowableIllegalArgumentException("Model tenant id is null");
}
this.tenantId = tenantId;
return this;
}
@Override
public ModelQuery modelTenantIdLike(String tenantIdLike) {
if (tenantIdLike == null) {
throw new FlowableIllegalArgumentException("Model tenant id is null");
}
this.tenantIdLike = tenantIdLike;
return this;
}
@Override
public ModelQuery modelWithoutTenantId() {
this.withoutTenantId = true;
return this;View on GitHub (pinned to d6d39ce1c6)