flowable/flowable-engine · error · FlowableException
Tenant mismatch between Historic Case Instance ('${historicC
Error message
Tenant mismatch between Historic Case Instance ('${historicCaseInstance.getTenantId()}') and Case Definition ('${destinationTenantId}') to migrate to What it means
doMigrateHistoricCaseInstance enforces tenant consistency: if the historic case instance's tenant differs from the target case definition's tenant, migration proceeds only when fallback-to-default-tenant is enabled AND the default tenant provider returns the destination tenant; otherwise this FlowableException is thrown.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/migration/CaseInstanceMigrationManagerImpl.java:354
}
}
if (document.getPostUpgradeExpression() != null && !document.getPostUpgradeExpression().isEmpty()) {
cmmnEngineConfiguration.getExpressionManager().createExpression(document.getPostUpgradeExpression()).getValue(caseInstance);
}
}
protected void doMigrateHistoricCaseInstance(HistoricCaseInstanceEntity historicCaseInstance, CaseDefinition caseDefinitionToMigrateTo, HistoricCaseInstanceMigrationDocument document, CommandContext commandContext) {
LOGGER.debug("Start migration of historic case instance with Id:'{}' to case definition identified by {}", historicCaseInstance.getId(), printCaseDefinitionIdentifierMessage(document));
String destinationTenantId = caseDefinitionToMigrateTo.getTenantId();
if (!Objects.equals(historicCaseInstance.getTenantId(), destinationTenantId)) {
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
if (cmmnEngineConfiguration.isFallbackToDefaultTenant() && cmmnEngineConfiguration.getDefaultTenantProvider() != null) {
if (!Objects.equals(destinationTenantId, cmmnEngineConfiguration.getDefaultTenantProvider().getDefaultTenant(historicCaseInstance.getId(), ScopeTypes.CMMN, caseDefinitionToMigrateTo.getKey()))) {
throw new FlowableException("Tenant mismatch between Historic Case Instance ('" + historicCaseInstance.getTenantId() + "') and Case Definition ('" + destinationTenantId + "') to migrate to");
}
} else {
throw new FlowableException("Tenant mismatch between Historic Case Instance ('" + historicCaseInstance.getTenantId() + "') and Case Definition ('" + destinationTenantId + "') to migrate to");
}
}
LOGGER.debug("Updating case definition reference of case root execution with id:'{}' to '{}'", historicCaseInstance.getId(), caseDefinitionToMigrateTo.getId());
String originalCaseDefinitionId = historicCaseInstance.getCaseDefinitionId();
historicCaseInstance.setCaseDefinitionId(caseDefinitionToMigrateTo.getId());
historicCaseInstance.setCaseDefinitionKey(caseDefinitionToMigrateTo.getKey());
historicCaseInstance.setCaseDefinitionName(caseDefinitionToMigrateTo.getName());
historicCaseInstance.setCaseDefinitionVersion(caseDefinitionToMigrateTo.getVersion());
historicCaseInstance.setCaseDefinitionDeploymentId(caseDefinitionToMigrateTo.getDeploymentId());
CommandContextUtil.getHistoricCaseInstanceEntityManager(commandContext).update(historicCaseInstance);
LOGGER.debug("Updating case definition reference in history");
changeCaseDefinitionReferenceForHistoricCaseInstance(historicCaseInstance, caseDefinitionToMigrateTo, commandContext);View on GitHub (pinned to d6d39ce1c6)
Solutions
- Migrate to a case definition deployed under the same tenant as the historic instances
- Enable fallback: cmmnEngineConfiguration.setFallbackDefaultTenant(true) and set a DefaultTenantProvider that returns destinationTenantId for the instance/scope
- Change the destination definition's tenant to match the historic instances' tenant
- Re-tag historic instances' tenant data if a cross-tenant move is genuinely required
Example fix
// before cmmnEngineConfiguration.setFallbackDefaultTenant(false); // mismatch throws // after cmmnEngineConfiguration.setFallbackDefaultTenant(true); cmmnEngineConfiguration.setDefaultTenantProvider((caseInstanceId, scopeType, caseDefinitionKey) -> destinationTenantId);
Defensive patterns
Strategy: validation
Validate before calling
const hist = historyService.createHistoricCaseInstanceQuery().caseInstanceId(id).singleResult();
if (hist.tenantId !== targetDefinition.tenantId && !engineConfig.fallbackDefaultTenant) {
throw new Error(`Tenant mismatch: instance '${hist.tenantId}' vs definition '${targetDefinition.tenantId}'`);
} Type guard
function tenantsCompatible(h, def, fallback, provider) { return h.tenantId === def.tenantId || (fallback && provider && provider.getDefaultTenant(h.id, 'cmmn', def.key) === def.tenantId); } Try / catch
try { migrateHistoricCaseInstance(id, doc); } catch (e) { if (String(e.message).startsWith('Tenant mismatch between Historic Case Instance')) { alignTenantOrEnableFallback(e); } else { throw e; } } Prevention
- Keep target case definitions deployed under the same tenant as the historic data
- If cross-tenant migration is needed, configure fallbackDefaultTenant with a matching DefaultTenantProvider before migrating
- Audit tenantId values in both definitions and historic rows as part of migration dry-run
When it happens
Trigger: Migrating a historic case instance to a case definition with a different tenantId, while cmmnEngineConfiguration.isFallbackToDefaultTenant() is false, or it is true but getDefaultTenantProvider().getDefaultTenant(...) does not equal the destination tenantId.
Common situations: Multi-tenant deployments where the historic data lives under tenant 'a' but the new definition was deployed to tenant 'b'; enabling fallback without configuring a DefaultTenantProvider that maps the instance to the destination tenant; moving cases across tenants during a reorganization.
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
- Must specify a case definition tenant id to migrate
- Tenant mismatch between Case Instance ('${caseInstance.getTe
- Tenant mismatch between Process Instance ('" + processInstan
- no SMTP host is configured for the mail server for tenant {t
- No case definition found for key '${caseDefinitionKey}'. Fal
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/26217f7cbc123755.
Report an issue: GitHub.