flowable/flowable-engine · error · FlowableException

Must specify a process definition key to migrate

Error message

Must specify a process definition key to migrate

What it means

The key/version/tenant constructor of ProcessInstanceMigrationValidationCmd validates all instances of a definition identified by key and version. It throws when the processDefinitionKey argument is null, because a null key cannot identify any process definition. This is a constructor-level precondition check.

Solutions

  1. Supply the actual process definition key from the BPMN model (the id attribute of <process>), not the definition id or name
  2. Null-check configuration before calling; fail early with a clear message if the key is missing
  3. Prefer the public API migrateToProcessDefinition(key, version, tenantId) on the migration builder, which routes through this constructor correctly

Example fix

// before
String key = config.get("migration.key"); // null when unset
new ProcessInstanceMigrationValidationCmd(key, 2, tenantId, doc);
// after
String key = config.get("migration.key");
if (key != null && !key.isEmpty()) {
    new ProcessInstanceMigrationValidationCmd(key, 2, tenantId, doc);
}
Defensive patterns

Strategy: validation

Validate before calling

if (processDefinitionKey == null || processDefinitionKey.isEmpty()) {
    throw new IllegalArgumentException("processDefinitionKey must match the <process> id in the BPMN model");
}

Type guard

boolean hasDefinitionKey(String key) { return key != null && !key.isEmpty(); }

Try / catch

try {
    validationCmd.execute(commandContext);
} catch (FlowableException e) {
    if (e.getMessage().contains("Must specify a process definition key")) {
        // load key from config/BPMN model and retry
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling new ProcessInstanceMigrationValidationCmd(null, version, tenantId, document) directly, or passing a null key variable obtained from configuration or a lookup that missed.

Common situations: Externalized config (properties/YAML) missing the definition key so the injected value is null; renaming a process definition in the model without updating caller configuration; direct use of internal command classes.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/ProcessInstanceMigrationValidationCmd.java:61

        this.processInstanceMigrationDocument = processInstanceMigrationDocument;
    }

    public ProcessInstanceMigrationValidationCmd(ProcessInstanceMigrationDocument processInstanceMigrationDocument, String processDefinitionId) {
        if (processDefinitionId == null) {
            throw new FlowableException("Must specify a process definition id to migrate");
        }
        
        if (processInstanceMigrationDocument == null) {
            throw new FlowableException("Must specify a process migration document to migrate");
        }

        this.processDefinitionId = processDefinitionId;
        this.processInstanceMigrationDocument = processInstanceMigrationDocument;
    }

    public ProcessInstanceMigrationValidationCmd(String processDefinitionKey, int processDefinitionVersion, String processDefinitionTenantId, ProcessInstanceMigrationDocument processInstanceMigrationDocument) {
        if (processDefinitionKey == null) {
            throw new FlowableException("Must specify a process definition key to migrate");
        }
        
        if (processInstanceMigrationDocument == null) {
            throw new FlowableException("Must specify a process migration document to migrate");
        }

        this.processDefinitionKey = processDefinitionKey;
        this.processDefinitionVersion = processDefinitionVersion;
        this.processInstanceMigrationDocument = processInstanceMigrationDocument;
        this.processDefinitionTenantId = processDefinitionTenantId;
    }

    @Override
    public ProcessInstanceMigrationValidationResult execute(CommandContext commandContext) {

        ProcessInstanceMigrationManager migrationManager = CommandContextUtil.getProcessEngineConfiguration(commandContext).getProcessInstanceMigrationManager();

        if (processInstanceId != null) {

View on GitHub (pinned to d6d39ce1c6)