flowable/flowable-engine · error · FlowableException
deleting historic process instances with related data…
Error message
deleting historic process instances with related data requires CommandExecutor
What it means
Flowable throws this FlowableException from HistoricProcessInstanceQueryImpl.delete when deleting historic process instances with related data but the query was constructed without a CommandExecutor. Deleting related data (tasks, activity data, related content) is executed as separate REQUIRES_NEW commands that need a real command executor; a detached query built manually has none.
Solutions
- Obtain the query via processEngine.getHistoryService().createHistoricProcessInstanceQuery() so it carries the engine's CommandExecutor
- If constructing manually, use a constructor that accepts the CommandContext or CommandExecutor
- In tests, build the query from a real ProcessEngine (or mock the command executor) before calling delete
Example fix
// before
HistoricProcessInstanceQueryImpl q = new HistoricProcessInstanceQueryImpl();
q.delete();
// after
HistoricProcessInstanceQuery q = historyService.createHistoricProcessInstanceQuery()
.finishedBefore(date);
q.delete(); Defensive patterns
Strategy: validation
Validate before calling
if (query instanceof HistoricProcessInstanceQueryImpl
&& ((HistoricProcessInstanceQueryImpl) query).getCommandExecutor() == null) {
throw new IllegalStateException("Query must be created via HistoryService to support delete()");
} Type guard
boolean isDeletableQuery(HistoricProcessInstanceQuery q) {
return q instanceof HistoricProcessInstanceQueryImpl
&& ((HistoricProcessInstanceQueryImpl) q).getCommandExecutor() != null;
} Try / catch
try {
query.delete();
} catch (FlowableException e) {
throw new IllegalStateException("Rebuild the query via historyService.createHistoricProcessInstanceQuery()", e);
} Prevention
- Always obtain queries from HistoryService rather than instantiating HistoricProcessInstanceQueryImpl directly
- Never call delete() on manually constructed or deserialized query objects
- In tests, build queries through a real ProcessEngine-backed service
When it happens
Trigger: Calling query.delete() on a HistoricProcessInstanceQueryImpl created with the no-arg/partial constructor (no commandExecutor injected) instead of obtaining the query from runtimeService.createHistoricProcessInstanceQuery().
Common situations: Unit tests or custom code instantiating HistoricProcessInstanceQueryImpl directly with new and invoking delete; deserializing a query object and calling delete without wiring the engine services.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
- batch entity not found for id
- BPMN engine has not been initialized
- Cannot read default EL properties
- CMMN engine has not been initialized
- Comment with id '' doesn't exists.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/32aae0fbc3df9a49.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/HistoricProcessInstanceQueryImpl.java:1296
@Override
public void delete() {
if (commandExecutor != null) {
commandExecutor.execute(new DeleteHistoricProcessInstancesCmd(this));
} else {
new DeleteHistoricProcessInstancesCmd(this).execute(Context.getCommandContext());
}
}
@Override
@Deprecated
public void deleteWithRelatedData() {
if (commandExecutor != null) {
CommandConfig config = new CommandConfig().transactionRequiresNew();
commandExecutor.execute(config, new DeleteHistoricProcessInstancesCmd(this));
commandExecutor.execute(config, new DeleteTaskAndActivityDataOfRemovedHistoricProcessInstancesCmd());
commandExecutor.execute(config, new DeleteRelatedDataOfRemovedHistoricProcessInstancesCmd());
} else {
throw new FlowableException("deleting historic process instances with related data requires CommandExecutor");
}
}
@Override
public String deleteInParallelUsingBatch(int batchSize, String batchName) {
return commandExecutor.execute(new DeleteHistoricProcessInstancesUsingBatchesCmd(this, batchSize, batchName, false));
}
@Override
public String deleteSequentiallyUsingBatch(int batchSize, String batchName) {
return commandExecutor.execute(new DeleteHistoricProcessInstancesUsingBatchesCmd(this, batchSize, batchName, true));
}
public String getBusinessKey() {
return businessKey;
}
public String getBusinessKeyLike() {View on GitHub (pinned to d6d39ce1c6)