flowable/flowable-engine · error · FlowableIllegalArgumentException
The target tenant id must not be null.
Error message
The target tenant id must not be null.
What it means
Flowable throws FlowableIllegalArgumentException when constructing a ChangeTenantIdBuilderImpl with a null targetTenantId. The builder moves data between tenants, so both source and target tenant ids must be valid strings. This is an eager constructor argument validation to fail fast before any data operations.
Source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/tenant/ChangeTenantIdBuilderImpl.java:35
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;
return this;
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Ensure the target tenant id string is non-null before calling changeTenantId(source, target)
- Check that the config/property/request parameter supplying the target tenant is actually populated
- Validate inputs at the application boundary and reject the operation early with a clear message
Example fix
// before
managementService.changeTenantId("tenantA", targetTenant);
// after
if (targetTenant == null) throw new IllegalArgumentException("targetTenant is required");
managementService.changeTenantId("tenantA", targetTenant); Defensive patterns
Strategy: validation
Validate before calling
if (sourceTenantId == null || targetTenantId == null) {
throw new IllegalArgumentException("source and target tenant ids are required");
} Type guard
boolean hasTenantIds(String s, String t) {
return s != null && !s.trim().isEmpty() && t != null && !t.trim().isEmpty();
} Try / catch
try {
managementService.changeTenantId(sourceTenantId, targetTenantId);
} catch (FlowableIllegalArgumentException e) {
logger.error("Invalid tenant change request: {}", e.getMessage());
} Prevention
- Validate tenant ids at the API/config boundary before calling the engine
- Fail fast on missing tenant configuration at startup
- Log tenant ids passed to migrations for traceability
When it happens
Trigger: Calling ProcessEngineManagementService (or engine-specific) changeTenantId(sourceTenantId, null), or passing a null variable that flows into the new ChangeTenantIdBuilderImpl(source, target, manager) constructor.
Common situations: Tenant id read from config or request parameter that is null/missing; dynamically resolved tenant id not set in a multi-tenant deployment.
Related errors
- variableName is null
- caseInstanceId is null
- tenant id is null
- tenantId is null
- The source and the target tenant ids must be different.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/ba6c2cb5aee594f9.
Report an issue: GitHub.