flowable/flowable-engine · error · ActivitiIllegalArgumentException

processDefinition tenantId is null

Error message

processDefinition tenantId is null

What it means

ProcessDefinitionQueryImpl.processDefinitionTenantId(String) throws ActivitiIllegalArgumentException 'processDefinition tenantId is null' when the tenantId argument is null. In multi-tenant Flowable setups the tenant filter must be a concrete (possibly empty-string-means-no-tenant) value; null is rejected eagerly to keep the SQL predicate valid. This is a client-side argument contract violation.

Solutions

  1. Resolve the tenant id from the authenticated context before building the query; fail fast if absent
  2. If the intent is 'no tenant', pass the empty string "" (the engine convention) rather than null
  3. Make the tenant filter conditional when tenant isolation is not required
  4. Catch ActivitiIllegalArgumentException and return a clear 'tenant required' error

Example fix

// before
query.processDefinitionTenantId(tenantContext.currentTenantId()); // null in scheduler
// after
String tenantId = tenantContext.currentTenantId();
if (tenantId != null) {
    query.processDefinitionTenantId(tenantId);
} else {
    query.processDefinitionTenantIdWithoutTenant();
}
Defensive patterns

Strategy: validation

Validate before calling

if (tenantId == null) throw new IllegalArgumentException("tenantId is required (use \"\" for no tenant)");
query.processDefinitionTenantId(tenantId);

Type guard

boolean hasTenantContext(String t) { return t != null; }

Try / catch

try {
    query.processDefinitionTenantId(tenantId);
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().contains("tenantId is null")) {
        throw new BadRequestException("tenant context is required for this query");
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling ProcessDefinitionQuery.processDefinitionTenantId(null) — commonly when the tenant id comes from a security context, request header, or tenant resolver that returned null (e.g. code running outside a tenant-aware context).

Common situations: Multi-tenant apps where background jobs/schedulers have no tenant context; missing X-Tenant-ID header forwarding; tenantId field absent in config or JWT claims; migrating single-tenant code into a multi-tenant deployment.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/1a5864381c548dd0. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/ProcessDefinitionQueryImpl.java:256

        return this;
    }

    @Override
    public ProcessDefinitionQuery active() {
        this.suspensionState = SuspensionState.ACTIVE;
        return this;
    }

    @Override
    public ProcessDefinitionQuery suspended() {
        this.suspensionState = SuspensionState.SUSPENDED;
        return this;
    }

    @Override
    public ProcessDefinitionQuery processDefinitionTenantId(String tenantId) {
        if (tenantId == null) {
            throw new ActivitiIllegalArgumentException("processDefinition tenantId is null");
        }
        this.tenantId = tenantId;
        return this;
    }

    @Override
    public ProcessDefinitionQuery processDefinitionTenantIdLike(String tenantIdLike) {
        if (tenantIdLike == null) {
            throw new ActivitiIllegalArgumentException("process definition tenantId is null");
        }
        this.tenantIdLike = tenantIdLike;
        return this;
    }

    @Override
    public ProcessDefinitionQuery processDefinitionWithoutTenantId() {
        this.withoutTenantId = true;
        return this;

View on GitHub (pinned to d6d39ce1c6)