flowable/flowable-engine · error · ActivitiIllegalArgumentException

Set of process definition keys is empty

Error message

Set of process definition keys is empty

What it means

ProcessInstanceQuery.processDefinitionKeys() rejects an empty set of process definition keys. The library requires at least one key because an empty 'IN' clause would produce invalid or meaningless SQL when filtering process instances. Throwing early gives a clear ActivitiIllegalArgumentException instead of a confusing query failure later.

Solutions

  1. Guard the caller: only call processDefinitionKeys when the set is non-empty; otherwise skip adding that filter entirely.
  2. If an empty set means 'no filter', omit the call rather than passing the empty set.
  3. If an empty set should mean 'match nothing', use processDefinitionKeys with a sentinel key or handle the no-result case before querying.
  4. Catch ActivitiIllegalArgumentException around query construction to surface a friendly validation message to the user.

Example fix

// before
query.processDefinitionKeys(keys); // keys may be empty

// after
if (keys != null && !keys.isEmpty()) {
    query.processDefinitionKeys(keys);
}
Defensive patterns

Strategy: validation

Validate before calling

if (keys == null || keys.isEmpty()) {
    throw new IllegalArgumentException("processDefinitionKeys must contain at least one key");
}
query.processDefinitionKeys(keys);

Type guard

boolean isValidKeySet(Set<String> keys) {
    return keys != null && !keys.isEmpty();
}

Try / catch

try {
    query.processDefinitionKeys(keys);
} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {
    // handle empty/null key set, e.g. skip filter or return 400
}

Prevention

When it happens

Trigger: Calling processInstanceQuery().processDefinitionKeys(keys) with a non-null but empty Set<String>, e.g. new HashSet<>() or a set filtered down to zero entries before the query is built.

Common situations: Building queries dynamically from user-selected filters where no process definitions were selected; collecting keys from configuration or a database lookup that returned nothing; generics-era refactors where code previously passed null (handled separately) and now passes an empty collection.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/ProcessInstanceQueryImpl.java:282

        if (processDefinitionKey == null) {
            throw new ActivitiIllegalArgumentException("Process definition key is null");
        }

        if (inOrStatement) {
            this.currentOrQueryObject.processDefinitionKey = processDefinitionKey;
        } else {
            this.processDefinitionKey = processDefinitionKey;
        }
        return this;
    }

    @Override
    public ProcessInstanceQuery processDefinitionKeys(Set<String> processDefinitionKeys) {
        if (processDefinitionKeys == null) {
            throw new ActivitiIllegalArgumentException("Set of process definition keys is null");
        }
        if (processDefinitionKeys.isEmpty()) {
            throw new ActivitiIllegalArgumentException("Set of process definition keys is empty");
        }

        if (inOrStatement) {
            this.currentOrQueryObject.processDefinitionKeys = processDefinitionKeys;
        } else {
            this.processDefinitionKeys = processDefinitionKeys;
        }
        return this;
    }

    @Override
    public ProcessInstanceQueryImpl deploymentId(String deploymentId) {
        if (inOrStatement) {
            this.currentOrQueryObject.deploymentId = deploymentId;
        } else {
            this.deploymentId = deploymentId;
        }
        return this;

View on GitHub (pinned to d6d39ce1c6)