{"record":{"id":"5cbd6df79843bfa4","repo":"flowable/flowable-engine","slug":"tenant-mismatch-between-process-instance-pro","errorCode":null,"errorMessage":"Tenant mismatch between Process Instance ('\" + processInstanceExecution.getTenantId() + \"') and Process Definition ('\" + procDefTenantId + \"') to migrate to","messagePattern":"Tenant mismatch between Process Instance \\('\" \\+ processInstanceExecution\\.getTenantId\\(\\) \\+ \"'\\) and Process Definition \\('\" \\+ procDefTenantId \\+ \"'\\) to migrate to","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/migration/ProcessInstanceMigrationManagerImpl.java","lineNumber":632,"sourceCode":"        Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expression, (VariableContainer) processInstance, Collections.emptyList());\n        if (delegate instanceof ActivityBehavior) {\n            CommandContextUtil.getProcessEngineConfiguration(commandContext).getDelegateInterceptor().handleInvocation(new ActivityBehaviorInvocation((ActivityBehavior) delegate, (ExecutionEntityImpl) processInstance));\n        } else if (delegate instanceof JavaDelegate) {\n            CommandContextUtil.getProcessEngineConfiguration(commandContext).getDelegateInterceptor().handleInvocation(new JavaDelegateInvocation((JavaDelegate) delegate, (ExecutionEntityImpl) processInstance));\n        } else {\n            throw new FlowableIllegalArgumentException(\"Delegate expression \" + expression + \" did neither resolve to an implementation of \" + ActivityBehavior.class + \" nor \" + JavaDelegate.class);\n        }\n    }\n\n    protected List<ChangeActivityStateBuilderImpl> prepareChangeStateBuilders(ExecutionEntity processInstanceExecution, ProcessDefinition procDefToMigrateTo, ProcessInstanceMigrationDocument document, CommandContext commandContext) {\n        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);\n\n        // Check processDefinition tenant\n        String procDefTenantId = procDefToMigrateTo.getTenantId();\n        if (!isSameOrDefaultTenant(processInstanceExecution.getTenantId(), procDefToMigrateTo.getKey(), \n                procDefTenantId, CommandContextUtil.getProcessEngineConfiguration(commandContext))) {\n            \n            throw new FlowableException(\"Tenant mismatch between Process Instance ('\" + processInstanceExecution.getTenantId() + \"') and Process Definition ('\" + procDefTenantId + \"') to migrate to\");\n        }\n\n        List<ChangeActivityStateBuilderImpl> changeActivityStateBuilders = new ArrayList<>();\n        ChangeActivityStateBuilderImpl mainProcessChangeActivityStateBuilder = new ChangeActivityStateBuilderImpl();\n        mainProcessChangeActivityStateBuilder.processInstanceId(processInstanceExecution.getId());\n        changeActivityStateBuilders.add(mainProcessChangeActivityStateBuilder);\n\n        // Current executions to migrate...\n        Map<String, List<ExecutionEntity>> filteredExecutionsByActivityId = executionEntityManager.findChildExecutionsByProcessInstanceId(processInstanceExecution.getId())\n            .stream()\n            .filter(executionEntity -> executionEntity.getCurrentActivityId() != null)\n            .filter(executionEntity -> !(executionEntity.getCurrentFlowElement() instanceof SubProcess))\n            .filter(executionEntity -> !(executionEntity.getCurrentFlowElement() instanceof BoundaryEvent))\n            .collect(Collectors.groupingBy(ExecutionEntity::getCurrentActivityId));\n\n        LOGGER.debug(\"Preparing ActivityChangeState builder for '{}' distinct activities\", filteredExecutionsByActivityId.size());\n\n        HashMap<String, ActivityMigrationMapping> mainProcessActivityMappingByFromActivityId = new HashMap<>();","sourceCodeStart":614,"sourceCodeEnd":650,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/migration/ProcessInstanceMigrationManagerImpl.java#L614-L650","documentation":"FlowableException thrown when the tenant id of the running process instance does not match, and is not a permitted default, the tenant id of the target process definition during instance migration. Migration is tenant-checked because tenant is part of process definition isolation. Thrown by isSameOrDefaultTenant check in prepareChangeStateBuilders.","triggerScenarios":"Calling ProcessInstanceMigrationBuilder.migrateToProcessDefinition(defId) where the target definition's tenant differs from the instance's tenant and no tenant-validated definition exists.","commonSituations":"Multi-tenant deployments where the target definition was deployed under a different tenant; deploying a new version of a definition without setting the same tenant; accidentally targeting a definition from tenant A for a tenant B instance.","solutions":["Migrate to a definition deployed with the same tenant id as the process instance","Redeploy the target process definition with the instance's tenant id","If instance tenant is the default (empty), ensure a definition for the given key exists for that default tenant","Use the tenant-aware migration API (migrateToProcessDefinition with tenant validation) and verify tenants first"],"exampleFix":"// before\nrepositoryService.createDeployment().addClasspathResource(\"orderProcess.bpmn20.xml\").deploy(); // no tenant\n// after\nrepositoryService.createDeployment().addClasspathResource(\"orderProcess.bpmn20.xml\").tenantId(\"tenant-A\").deploy();","handlingStrategy":"validation","validationCode":"ProcessDefinition procDef = repositoryService.getProcessDefinition(targetDefId);\nProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();\nif (!procDef.getTenantId().equals(pi.getTenantId())) {\n    throw new IllegalStateException(\"Tenant mismatch: \" + pi.getTenantId() + \" vs \" + procDef.getTenantId());\n}","typeGuard":"boolean sameTenant(String instanceTenant, String defTenant) {\n    return instanceTenant == null ? defTenant.isEmpty() : instanceTenant.equals(defTenant);\n}","tryCatchPattern":"try {\n    migrationBuilder.migrate(instanceId);\n} catch (FlowableException e) {\n    if (e.getMessage().startsWith(\"Tenant mismatch\")) {\n        // deploy/redeploy target definition under the instance tenant\n    }\n}","preventionTips":["Set tenantId on every deployment in multi-tenant apps","Query candidate definitions with tenantId filters before migrating","Add tenant checks to CI tests for migration scenarios","Keep tenant conventions (default vs explicit) documented and enforced"],"tags":["flowable","tenant","migration","multi-tenancy"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}