{"record":{"id":"fe11a329acbf2fb7","repo":"octobercms/october","slug":"invalid-order-rule-type","errorCode":null,"errorMessage":"Invalid order rule type","messagePattern":"Invalid order rule type","errorType":"exception","errorClass":"SystemException","httpStatus":null,"severity":"error","filePath":"modules/dashboard/classes/ReportQueryBuilder.php","lineNumber":966,"sourceCode":"     *\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())\n                    ->getDataSetColumName(),\n\n            ReportDataOrderRule::ATTR_TYPE_DIMENSION_FIELD =>\n                $this->dimension->findDimensionFieldByCode($this->orderRule->getAttributeName())->getCode(),\n\n            default => throw new SystemException('Invalid order rule type')\n        };\n\n        $query->orderBy(\n            $this->evalDbObjectName($columnName),\n            $this->orderRule->isAscending() ? 'asc' : 'desc'\n        );\n    }\n\n    /**\n     * evalDbObjectName validates and trims a database object name\n     *\n     * @param string $name\n     * @return string\n     */\n    protected function evalDbObjectName(string $name): string\n    {\n        return trim($name);\n    }","sourceCodeStart":948,"sourceCodeEnd":984,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/dashboard/classes/ReportQueryBuilder.php#L948-L984","documentation":"ReportQueryBuilder::applyOrderRule() maps the order rule's data attribute type to an ORDER BY column: dimension, metric (resolved via findMetricByCodeStrict) or dimension_field. Any other value from the order rule's getDataAttributeType() hits default and throws SystemException('Invalid order rule type'). Order rules arrive from dashboard/widget definitions or request payloads, so this is almost always malformed or stale sorting configuration rather than a code bug in the builder.","triggerScenarios":"A report data request sends orderBy/orderByDimension payload where the attribute type is missing, empty or invented ('attr', 'column'); composing a ReportDataOrderRule manually without setting the type; old saved dashboard definition using a pre-rename type value.","commonSituations":"Front-end builds its own sort payload instead of using the widget's helper; API consumers guessing the schema; dashboard definitions persisted before an upgrade where the order-rule format changed.","solutions":["Set the order rule type to one of ReportDataOrderRule::ATTR_TYPE_DIMENSION / ATTR_TYPE_METRIC / ATTR_TYPE_DIMENSION_FIELD when constructing the rule.","Validate sort payloads at the controller boundary and reject unknown types with a 422-style response instead of letting them reach the builder.","Update or reset saved dashboard definitions after upgrading so order rules use the current format.","When ordering by a metric, also verify the metric code exists on the data source (unknown codes throw 'Unknown metric' from the same code path)."],"exampleFix":"// before\n$orderRule = new ReportDataOrderRule;\n$orderRule->setAttributeName('status'); // type never set\n\n// after\n$orderRule = new ReportDataOrderRule;\n$orderRule->setDataAttributeType(ReportDataOrderRule::ATTR_TYPE_DIMENSION);\n$orderRule->setAttributeName('status');\n$orderRule->setIsAscending(true);","handlingStrategy":"validation","validationCode":"$validOrderTypes = [\n    ReportDataOrderRule::ATTR_TYPE_DIMENSION,\n    ReportDataOrderRule::ATTR_TYPE_METRIC,\n    ReportDataOrderRule::ATTR_TYPE_DIMENSION_FIELD,\n];\n$order = $payload['orderBy'] ?? null;\nif ($order !== null) {\n    $type = $order['attribute']['type'] ?? null;\n    if (!in_array($type, $validOrderTypes, true)) {\n        throw new InvalidArgumentException('Invalid order rule attribute type.');\n    }\n    // if ordering by metric, also confirm the code exists\n    if ($type === ReportDataOrderRule::ATTR_TYPE_METRIC) {\n        ReportMetric::findMetricByCodeStrict($metrics, $order['attribute']['name'], false)\n            ?? throw new InvalidArgumentException('Unknown metric in order rule.');\n    }\n}","typeGuard":"function isValidOrderRuleType(mixed $type): bool\n{\n    return is_string($type) && in_array($type, [\n        ReportDataOrderRule::ATTR_TYPE_DIMENSION,\n        ReportDataOrderRule::ATTR_TYPE_METRIC,\n        ReportDataOrderRule::ATTR_TYPE_DIMENSION_FIELD,\n    ], true);\n}","tryCatchPattern":null,"preventionTips":["Construct order rules with the ATTR_TYPE_* constants only.","Validate sort payloads before they reach the query builder.","Reset saved dashboard definitions when the order-rule payload schema changes."],"tags":["dashboard","report-query-builder","order-rule","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"}