flowable/flowable-engine · error · ActivitiIllegalArgumentException

processInstanceId is null

Error message

processInstanceId is null

What it means

DeleteHistoricProcessInstanceCmd deletes a historic process instance by id and first checks that the id is non-null, throwing ActivitiIllegalArgumentException otherwise. Historic cleanup requires an explicit instance id.

Solutions

  1. Pass a valid non-null processInstanceId
  2. Filter out null ids in cleanup loops before invoking
  3. Validate the id in the calling layer (REST param / DTO)

Example fix

// before
historyService.deleteHistoricProcessInstance(instanceId);
// after
if (instanceId != null) {
    historyService.deleteHistoricProcessInstance(instanceId);
}
Defensive patterns

Strategy: validation

Validate before calling

if (processInstanceId == null || processInstanceId.isEmpty()) return; // or throw
boolean exists = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).count() > 0;

Type guard

boolean hasInstanceId(String id) { return id != null && !id.trim().isEmpty(); }

Try / catch

try { historyService.deleteHistoricProcessInstance(id); } catch (ActivitiIllegalArgumentException e) { log.warn("Skipping historic delete: {}", e.getMessage()); }

Prevention

When it happens

Trigger: historyService.deleteHistoricProcessInstance(processInstanceId) with null id — e.g. an uninitialized variable, an API caller omitting the id, or a batch cleaner iterating records where the id field is null.

Common situations: Retention/cleanup jobs reading ids from a report where some rows have null ids; REST handlers missing a body field; wrong getter returning the wrong column.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/cmd/DeleteHistoricProcessInstanceCmd.java:40

import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;

/**
 * @author Frederik Heremans
 */
public class DeleteHistoricProcessInstanceCmd implements Command<Object>, Serializable {

    private static final long serialVersionUID = 1L;
    protected String processInstanceId;

    public DeleteHistoricProcessInstanceCmd(String processInstanceId) {
        this.processInstanceId = processInstanceId;
    }

    @Override
    public Object execute(CommandContext commandContext) {
        if (processInstanceId == null) {
            throw new ActivitiIllegalArgumentException("processInstanceId is null");
        }
        // Check if process instance is still running
        HistoricProcessInstance instance = commandContext
                .getHistoricProcessInstanceEntityManager()
                .findHistoricProcessInstance(processInstanceId);

        if (instance == null) {
            throw new ActivitiObjectNotFoundException("No historic process instance found with id: " + processInstanceId, HistoricProcessInstance.class);
        }
        if (instance.getEndTime() == null) {
            throw new ActivitiException("Process instance is still running, cannot delete historic process instance: " + processInstanceId);
        }

        commandContext
                .getHistoricProcessInstanceEntityManager()
                .deleteHistoricProcessInstanceById(processInstanceId);

        return null;

View on GitHub (pinned to d6d39ce1c6)