flowable/flowable-engine · error · FlowableIllegalArgumentException

The source tenant id must not be null.

Error message

The source tenant id must not be null.

What it means

ChangeTenantIdBuilderImpl's constructor validates its arguments: a null sourceTenantId or targetTenantId throws FlowableIllegalArgumentException('The source tenant id must not be null.'). Tenant ids are used as query keys when moving definitions between tenants, so nulls are rejected immediately.

Solutions

  1. Pass non-null string tenant ids, e.g. createChangeTenantIdBuilder("sourceTenant", "targetTenant").
  2. Validate tenant ids at the API/UI layer before invoking the builder.
  3. Replace null with the actual tenant key or fail early with a domain-specific message.

Example fix

// before
String from = request.getParameter("sourceTenant"); // may be null
managementService.createChangeTenantIdBuilder(from, to).execute();

// after
String from = request.getParameter("sourceTenant");
if (from == null || to == null) throw new BadRequestException("sourceTenant and targetTenant are required");
managementService.createChangeTenantIdBuilder(from, to).execute();
Defensive patterns

Strategy: validation

Validate before calling

if (sourceTenantId == null || targetTenantId == null) {
    throw new IllegalArgumentException("sourceTenantId and targetTenantId must be non-null");
}

Type guard

boolean validTenants(String src, String tgt) { return src != null && tgt != null; }

Try / catch

try {
    managementService.createChangeTenantIdBuilder(src, tgt).execute();
} catch (FlowableIllegalArgumentException e) {
    throw new BadRequestException("Tenant ids must be provided: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling managementService.createChangeTenantIdBuilder(null, target) (or passing a null that came from an unset variable/config) — first hit is the source-id check at line 32.

Common situations: Tenant ids read from a database row or request parameter that is null; refactoring where constants were removed; code paths constructing the builder from nullable user input.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/tenant/ChangeTenantIdBuilderImpl.java:32

import org.flowable.common.engine.api.FlowableIllegalArgumentException;
import org.flowable.common.engine.api.tenant.ChangeTenantIdBuilder;
import org.flowable.common.engine.api.tenant.ChangeTenantIdResult;

/**
 * @author Filip Hrisafov
 */
public class ChangeTenantIdBuilderImpl implements ChangeTenantIdBuilder {

    protected final String sourceTenantId;
    protected final String targetTenantId;
    protected final ChangeTenantIdManager changeTenantIdManager;

    protected String definitionTenantId;

    public ChangeTenantIdBuilderImpl(String sourceTenantId, String targetTenantId, ChangeTenantIdManager changeTenantIdManager) {
        if (sourceTenantId == null) {
            throw new FlowableIllegalArgumentException("The source tenant id must not be null.");
        }
        if (targetTenantId == null) {
            throw new FlowableIllegalArgumentException("The target tenant id must not be null.");
        }
        this.sourceTenantId = sourceTenantId;
        this.targetTenantId = targetTenantId;
        if (sourceTenantId.equals(targetTenantId)) {
            throw new FlowableIllegalArgumentException("The source and the target tenant ids must be different.");
        }
        this.changeTenantIdManager = changeTenantIdManager;
    }

    @Override
    public ChangeTenantIdBuilder definitionTenantId(String definitionTenantId) {
        if (definitionTenantId == null) {
            throw new FlowableIllegalArgumentException("definitionTenantId must not be null");
        }
        this.definitionTenantId = definitionTenantId;

View on GitHub (pinned to d6d39ce1c6)