flowable/flowable-engine · error · FlowableIllegalArgumentException
processDefinitionId is null
Error message
processDefinitionId is null
What it means
GetProcessDefinitionInfoCmd's sibling for history levels: execute throws FlowableIllegalArgumentException('processDefinitionId is null') when the constructor argument is null. The command resolves the history level defined in a process definition's model, which requires an id. Fail-fast argument validation before any lookup.
Solutions
- Guard the id before invoking and throw/return with a clear message
- Ensure the variable is populated from processEngineConfiguration or a deployment result before use
- Check the upstream lookup (definition query) that produced the null id
- Add an assertion/unit test covering the null-id path
Example fix
// before
HistoryLevel level = engineConfig.getHistoryLevel(processDefinitionId); // id may be null
// after
if (processDefinitionId == null) {
throw new IllegalArgumentException("Cannot resolve history level: processDefinitionId is null");
}
HistoryLevel level = engineConfig.getHistoryLevel(processDefinitionId); Defensive patterns
Strategy: validation
Validate before calling
if (processDefinitionId == null) {
throw new IllegalStateException("processDefinitionId must be resolved before reading history level");
} Try / catch
try {
HistoryLevel level = getHistoryLevelForProcessDefinition(defId);
} catch (FlowableIllegalArgumentException e) {
level = defaultHistoryLevel;
} Prevention
- Never pass through ids from lookups that may return null without checking
- Assert non-null id in the code path that builds the command
- Cover the null-id branch in unit tests
When it happens
Trigger: Invoking the dynamic history-level lookup (e.g. via process engine configuration's getHistoryLevel(processDefinitionId)) with a null id — usually an unset variable or a lookup chain that returned null upstream.
Common situations: Configuration code that resolves the definition id conditionally and proceeds even when resolution failed; refactored code paths where the id assignment was removed; programmatic engine bootstrapping passing null defaults.
Related errors
- appsDefinitionIds is null
- at least one of userId or groups must be provided
- Business status is null
- Candidate user is null
- Case definition keys is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/5cb09750941c6f30.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/GetProcessDefinitionHistoryLevelModelCmd.java:45
import org.flowable.engine.repository.ProcessDefinition;
/**
* @author Tijs Rademakers
*/
public class GetProcessDefinitionHistoryLevelModelCmd implements Command<HistoryLevel>, Serializable {
private static final long serialVersionUID = 1L;
protected String processDefinitionId;
public GetProcessDefinitionHistoryLevelModelCmd(String processDefinitionId) {
this.processDefinitionId = processDefinitionId;
}
@Override
public HistoryLevel execute(CommandContext commandContext) {
if (processDefinitionId == null) {
throw new FlowableIllegalArgumentException("processDefinitionId is null");
}
HistoryLevel historyLevel = null;
ProcessDefinition processDefinition = CommandContextUtil.getProcessDefinitionEntityManager(commandContext).findById(processDefinitionId);
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);
Process process = bpmnModel.getProcessById(processDefinition.getKey());
if (process.getExtensionElements().containsKey("historyLevel")) {
ExtensionElement historyLevelElement = process.getExtensionElements().get("historyLevel").iterator().next();
String historyLevelValue = historyLevelElement.getElementText();
if (StringUtils.isNotEmpty(historyLevelValue)) {
try {
historyLevel = HistoryLevel.getHistoryLevelForKey(historyLevelValue);
} catch (Exception e) {
}View on GitHub (pinned to d6d39ce1c6)