flowable/flowable-engine · error · FlowableIllegalArgumentException

The source and the target tenant ids must be different.

Error message

The source and the target tenant ids must be different.

What it means

Flowable throws FlowableIllegalArgumentException when the source and target tenant ids passed to ChangeTenantIdBuilderImpl are equal. Moving data from a tenant to itself is a no-op or would corrupt the migration logic, so it is rejected upfront.

Source

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

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;
        return this;
    }

    @Override
    public ChangeTenantIdResult simulate() {
        return changeTenantIdManager.simulate(this);
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Verify the caller passes a genuinely different target tenant id
  2. Add an application-level check that source != target before invoking the builder
  3. Log both ids at the call site to diagnose why they are identical

Example fix

// before
managementService.changeTenantId(tenantId, tenantId);
// after
if (!tenantId.equals(newTenantId)) {
    managementService.changeTenantId(tenantId, newTenantId);
}
Defensive patterns

Strategy: validation

Validate before calling

if (sourceTenantId.equals(targetTenantId)) {
    throw new IllegalArgumentException("target must differ from source tenant");
}

Try / catch

try {
    managementService.changeTenantId(sourceTenantId, targetTenantId);
} catch (FlowableIllegalArgumentException e) {
    logger.warn("Source and target tenant must differ: {} -> {}", sourceTenantId, targetTenantId);
}

Prevention

When it happens

Trigger: Calling changeTenantId("tenantA", "tenantA"), or passing variables that happen to hold the same tenant id on both sides of the call.

Common situations: Target tenant id accidentally defaulted to the source tenant id; programmatic tenant selection where the same tenant is resolved twice; test code reusing one tenant constant.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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