flowable/flowable-engine · error · FlowableIllegalArgumentException
Variable operation is missing for variable: " +…
Error message
Variable operation is missing for variable: " + variable.getName()
What it means
When building a historic process instance query from REST query parameters, each variable filter must declare an operation (equals, like, gt, exists, ...). addVariables throws FlowableIllegalArgumentException if a QueryVariable has no variableOperation, because the query cannot know how to compare the value.
Solutions
- Use the correct variable query syntax including the operation, e.g. variable=name|eq|value
- Check supported QueryVariableOperation names and use exactly those (equals, notEquals, gt, gte, lt, lte, like, exists, notExists...)
- Catch FlowableIllegalArgumentException (HTTP 400) and validate variable filters client-side before issuing the query
Example fix
// before GET /history/historic-process-instances?variable=orderAmount|2500 // after GET /history/historic-process-instances?variable=orderAmount|equals|2500
Defensive patterns
Strategy: validation
Validate before calling
const OPS = ['equals','notEquals','gt','gte','lt','lte','like','exists','notExists'];
for (const v of variables) {
if (!v.operation || !OPS.includes(v.operation)) throw new Error(`Variable ${v.name}: missing/invalid operation`);
} Type guard
function hasOperation(v) { return v != null && typeof v.operation === 'string' && v.operation.length > 0; } Try / catch
try { return await queryHistoricInstances(vars); } catch (e) { if (e.status === 400) showFilterSyntaxHelp(e); else throw e; } Prevention
- Use the documented variable=name|op|value query syntax
- Centralize variable-filter construction in one helper
- Validate operator names against QueryVariableOperation enum values
When it happens
Trigger: GET /history/historic-process-instances with a variable query parameter (variable=..., scope) whose operation part is missing or misspelled, e.g. 'variable=name|value' without the operator segment.
Common situations: Hand-built query strings missing the operator segment; client library sending variable filters without mapping the operation; typo in operator name leading to parse failure.
Understand the failure class
Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.
Related errors
- Value-only query (without a variable-name) is only…
- Variable value is missing for variable: " +…
- A request body was expected when executing the form submit.
- Attachment name is required.
- Error converting request body to RestVariable instance
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/9debefa866f6ac0a.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/history/HistoricProcessInstanceBaseResource.java:313
restApiInterceptor.accessHistoryProcessInfoById(processInstance);
}
return processInstance;
}
protected HistoricProcessInstance getHistoricProcessInstanceFromRequestWithoutAccessCheck(String processInstanceId) {
HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (processInstance == null) {
throw new FlowableObjectNotFoundException("Could not find a process instance with id '" + processInstanceId + "'.", HistoricProcessInstance.class);
}
return processInstance;
}
protected void addVariables(HistoricProcessInstanceQuery processInstanceQuery, List<QueryVariable> variables) {
for (QueryVariable variable : variables) {
if (variable.getVariableOperation() == null) {
throw new FlowableIllegalArgumentException("Variable operation is missing for variable: " + variable.getName());
}
if (variable.getVariableOperation() != QueryVariableOperation.EXISTS && variable.getVariableOperation() != QueryVariableOperation.NOT_EXISTS) {
if (variable.getValue() == null) {
throw new FlowableIllegalArgumentException("Variable value is missing for variable: " + variable.getName());
}
}
boolean nameLess = variable.getName() == null;
Object actualValue = restResponseFactory.getVariableValue(variable);
// A value-only query is only possible using equals-operator
if (nameLess && variable.getVariableOperation() != QueryVariableOperation.EQUALS) {
throw new FlowableIllegalArgumentException("Value-only query (without a variable-name) is only supported when using 'equals' operation.");
}
switch (variable.getVariableOperation()) {
View on GitHub (pinned to d6d39ce1c6)