octobercms/october · error · SystemException
Invalid filter operation:
Error message
Invalid filter operation:
What it means
While translating a filter into SQL, ReportQueryBuilder::applyFilter() matches the filter's operation against the supported set: = , >= , <= , > , < , string_starts_with, string_includes, one_of. Anything else reaches default and throws SystemException('Invalid filter operation: <op>'). Operations are compared as raw strings via the ReportDimensionFilter::OPERATION_* constants, so both unknown values and malformed payloads (wrong key, nested object, array) trigger this.
Source
Thrown at modules/dashboard/classes/ReportQueryBuilder.php:942
default => throw new SystemException('Invalid filter attribute type')
};
$columnName = $this->evalDbObjectName($columnName);
$operation = $filter->getOperation();
$value = $filter->getValue();
match ($operation) {
ReportDimensionFilter::OPERATION_EQUALS,
ReportDimensionFilter::OPERATION_MORE_OR_EQUALS,
ReportDimensionFilter::OPERATION_LESS_OR_EQUALS,
ReportDimensionFilter::OPERATION_MORE,
ReportDimensionFilter::OPERATION_LESS => $query->where($columnName, $operation, $value),
ReportDimensionFilter::OPERATION_STARTS_WITH => $query->where($columnName, 'like', $value . '%'),
ReportDimensionFilter::OPERATION_STRING_INCLUDES => $query->where($columnName, 'like', '%' . $value . '%'),
ReportDimensionFilter::OPERATION_ONE_OF => $query->whereIn($columnName, $value),
default => throw new SystemException('Invalid filter operation: ' . $operation)
};
}
/**
* applyOrderRule applies ordering
*
* @param QueryBuilder $query
*/
protected function applyOrderRule(QueryBuilder $query): void
{
$columnName = match ($this->orderRule->getDataAttributeType()) {
ReportDataOrderRule::ATTR_TYPE_DIMENSION =>
($this->dimension->isDate() && $this->groupInterval !== ReportDataSourceBase::GROUP_INTERVAL_FULL)
? $this->dimension->getDataSetColumName()
: ($this->dimension->getLabelColumnName() ?? $this->dimension->getDatabaseColumnName()),
ReportDataOrderRule::ATTR_TYPE_METRIC =>
ReportMetric::findMetricByCodeStrict($this->metrics, $this->orderRule->getAttributeName())View on GitHub (pinned to b608633a7e)
Solutions
- Use one of: '=', '>=', '<=', '>', '<', 'string_starts_with', 'string_includes', 'one_of' — ideally via ReportDimensionFilter::OPERATION_* constants.
- Map UI operator names to API operations at the boundary (e.g. 'equals' => OPERATION_EQUALS, 'contains' => OPERATION_STRING_INCLUDES).
- Validate each filter payload before dispatch: reject/ignore filters whose operation is not in the allowed list.
- Trim whitespace and ensure the operation is a scalar string, not a nested structure.
Example fix
// before
$filter->setOperation('contains');
// after
$filter->setOperation(ReportDimensionFilter::OPERATION_STRING_INCLUDES); Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED_OPERATIONS = [
ReportDimensionFilter::OPERATION_EQUALS,
ReportDimensionFilter::OPERATION_MORE_OR_EQUALS,
ReportDimensionFilter::OPERATION_LESS_OR_EQUALS,
ReportDimensionFilter::OPERATION_MORE,
ReportDimensionFilter::OPERATION_LESS,
ReportDimensionFilter::OPERATION_STARTS_WITH,
ReportDimensionFilter::OPERATION_STRING_INCLUDES,
ReportDimensionFilter::OPERATION_ONE_OF,
];
$op = $payload['operation'] ?? null;
if (!is_string($op) || !in_array($op, ALLOWED_OPERATIONS, true)) {
throw new InvalidArgumentException("Unsupported filter operation: " . var_export($op, true));
}
$filter->setOperation($op); Type guard
function isValidFilterOperation(mixed $op): bool
{
return is_string($op) && in_array($op, [
'=', '>=', '<=', '>', '<',
ReportDimensionFilter::OPERATION_STARTS_WITH,
ReportDimensionFilter::OPERATION_STRING_INCLUDES,
ReportDimensionFilter::OPERATION_ONE_OF,
], true);
} Prevention
- Map UI operator vocabulary to OPERATION_* constants at the API boundary.
- Ensure operation values are scalar strings; reject arrays/objects in payload validation.
- Document the allowed operation list next to your front-end filter builder.
When it happens
Trigger: A dashboard request filter carrying 'operation': 'like', 'equals', 'in', '>' with surrounding whitespace, or a missing operation defaulting to something invalid; building ReportDimensionFilter programmatically and setting a SQL operator string where the semantic constant belongs ('=' works, 'EQ' does not).
Common situations: Front-end sends its own operator vocabulary that differs from the API constants; payload mangled by JSON serialization (operation becomes an array/object which stringifies oddly); stale cached widget config from before an operation was renamed.
Related errors
- Invalid filter attribute type
- Invalid aggregate function:
- Invalid order rule type
- Table name is required.
- Dimension is required.
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/61b22f7e2c459fc3.
Report an issue: GitHub.