flowable/flowable-engine · error · ActivitiIllegalArgumentException

activity tenant id is null

Error message

activity tenant id is null

What it means

HistoricActivityInstanceQueryImpl.activityTenantId(tenantId) validates that the tenant id used as an exact-match filter is not null. Tenant filtering by equality to null is not supported, so the library fails fast with ActivitiIllegalArgumentException. Use activityTenantIdWithoutTenant() if you specifically want activities with no tenant.

Solutions

  1. Pass a concrete tenant id string to activityTenantId().
  2. If the intent is 'no tenant', call activityTenantIdWithoutTenant() instead of passing null.
  3. Guard the call site: only invoke the query when TenantContext.getTenantId() is non-null.
  4. Propagate tenant id explicitly into async/job code paths where the context is lost.

Example fix

// before
String tenant = TenantContext.getTenantId(); // may be null
query.activityTenantId(tenant);
// after
String tenant = TenantContext.getTenantId();
if (tenant != null) {
    query.activityTenantId(tenant);
} else {
    query.activityTenantIdWithoutTenant();
}
Defensive patterns

Strategy: validation

Validate before calling

if (tenantId == null && !allowTenantless) throw new IllegalArgumentException("tenantId required for activityTenantId()");

Type guard

boolean hasTenant(String t) { return t != null && !t.isEmpty(); }

Try / catch

try {
    query.activityTenantId(tenantId);
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().contains("activity tenant id is null")) {
        query.activityTenantIdWithoutTenant(); // fallback for tenantless data
    }
}

Prevention

When it happens

Trigger: Calling historicActivityInstanceQuery.activityTenantId(null), typically when the tenant id comes from an unset context variable, a missing authenticated tenant, or an optional config value.

Common situations: Multi-tenant deployments where the tenant context is not populated (e.g. calling from a job or async executor without tenant context); users omitting the tenant in an API request; migrations from single-tenant setups.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/HistoricActivityInstanceQueryImpl.java:131

    @Override
    public HistoricActivityInstanceQueryImpl finished() {
        this.finished = true;
        this.unfinished = false;
        return this;
    }

    @Override
    public HistoricActivityInstanceQueryImpl unfinished() {
        this.unfinished = true;
        this.finished = false;
        return this;
    }

    @Override
    public HistoricActivityInstanceQueryImpl activityTenantId(String tenantId) {
        if (tenantId == null) {
            throw new ActivitiIllegalArgumentException("activity tenant id is null");
        }
        this.tenantId = tenantId;
        return this;
    }

    @Override
    public HistoricActivityInstanceQueryImpl activityTenantIdLike(String tenantIdLike) {
        if (tenantIdLike == null) {
            throw new ActivitiIllegalArgumentException("activity tenant id is null");
        }
        this.tenantIdLike = tenantIdLike;
        return this;
    }

    @Override
    public HistoricActivityInstanceQueryImpl activityWithoutTenantId() {
        this.withoutTenantId = true;
        return this;

View on GitHub (pinned to d6d39ce1c6)