{"record":{"id":"61b22f7e2c459fc3","repo":"octobercms/october","slug":"invalid-filter-operation-61b22f","errorCode":null,"errorMessage":"Invalid filter operation: ","messagePattern":"Invalid filter operation: ","errorType":"exception","errorClass":"SystemException","httpStatus":null,"severity":"error","filePath":"modules/dashboard/classes/ReportQueryBuilder.php","lineNumber":942,"sourceCode":"            default => throw new SystemException('Invalid filter attribute type')\n        };\n\n        $columnName = $this->evalDbObjectName($columnName);\n        $operation = $filter->getOperation();\n        $value = $filter->getValue();\n\n        match ($operation) {\n            ReportDimensionFilter::OPERATION_EQUALS,\n            ReportDimensionFilter::OPERATION_MORE_OR_EQUALS,\n            ReportDimensionFilter::OPERATION_LESS_OR_EQUALS,\n            ReportDimensionFilter::OPERATION_MORE,\n            ReportDimensionFilter::OPERATION_LESS => $query->where($columnName, $operation, $value),\n\n            ReportDimensionFilter::OPERATION_STARTS_WITH => $query->where($columnName, 'like', $value . '%'),\n            ReportDimensionFilter::OPERATION_STRING_INCLUDES => $query->where($columnName, 'like', '%' . $value . '%'),\n            ReportDimensionFilter::OPERATION_ONE_OF => $query->whereIn($columnName, $value),\n\n            default => throw new SystemException('Invalid filter operation: ' . $operation)\n        };\n    }\n\n    /**\n     * applyOrderRule applies ordering\n     *\n     * @param QueryBuilder $query\n     */\n    protected function applyOrderRule(QueryBuilder $query): void\n    {\n        $columnName = match ($this->orderRule->getDataAttributeType()) {\n            ReportDataOrderRule::ATTR_TYPE_DIMENSION =>\n                ($this->dimension->isDate() && $this->groupInterval !== ReportDataSourceBase::GROUP_INTERVAL_FULL)\n                    ? $this->dimension->getDataSetColumName()\n                    : ($this->dimension->getLabelColumnName() ?? $this->dimension->getDatabaseColumnName()),\n\n            ReportDataOrderRule::ATTR_TYPE_METRIC =>\n                ReportMetric::findMetricByCodeStrict($this->metrics, $this->orderRule->getAttributeName())","sourceCodeStart":924,"sourceCodeEnd":960,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/dashboard/classes/ReportQueryBuilder.php#L924-L960","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\n$filter->setOperation('contains');\n\n// after\n$filter->setOperation(ReportDimensionFilter::OPERATION_STRING_INCLUDES);","handlingStrategy":"validation","validationCode":"const ALLOWED_OPERATIONS = [\n    ReportDimensionFilter::OPERATION_EQUALS,\n    ReportDimensionFilter::OPERATION_MORE_OR_EQUALS,\n    ReportDimensionFilter::OPERATION_LESS_OR_EQUALS,\n    ReportDimensionFilter::OPERATION_MORE,\n    ReportDimensionFilter::OPERATION_LESS,\n    ReportDimensionFilter::OPERATION_STARTS_WITH,\n    ReportDimensionFilter::OPERATION_STRING_INCLUDES,\n    ReportDimensionFilter::OPERATION_ONE_OF,\n];\n\n$op = $payload['operation'] ?? null;\nif (!is_string($op) || !in_array($op, ALLOWED_OPERATIONS, true)) {\n    throw new InvalidArgumentException(\"Unsupported filter operation: \" . var_export($op, true));\n}\n$filter->setOperation($op);","typeGuard":"function isValidFilterOperation(mixed $op): bool\n{\n    return is_string($op) && in_array($op, [\n        '=', '>=', '<=', '>', '<',\n        ReportDimensionFilter::OPERATION_STARTS_WITH,\n        ReportDimensionFilter::OPERATION_STRING_INCLUDES,\n        ReportDimensionFilter::OPERATION_ONE_OF,\n    ], true);\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["dashboard","report-query-builder","filter-validation","enum-value-not-allowed"],"backgroundTag":"enum-value-not-allowed","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}