octobercms/october · error · SystemException

Invalid order rule type

Error message

Invalid order rule type

What it means

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.

Source

Thrown at modules/dashboard/classes/ReportQueryBuilder.php:966

     *
     * @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())
                    ->getDataSetColumName(),

            ReportDataOrderRule::ATTR_TYPE_DIMENSION_FIELD =>
                $this->dimension->findDimensionFieldByCode($this->orderRule->getAttributeName())->getCode(),

            default => throw new SystemException('Invalid order rule type')
        };

        $query->orderBy(
            $this->evalDbObjectName($columnName),
            $this->orderRule->isAscending() ? 'asc' : 'desc'
        );
    }

    /**
     * evalDbObjectName validates and trims a database object name
     *
     * @param string $name
     * @return string
     */
    protected function evalDbObjectName(string $name): string
    {
        return trim($name);
    }

View on GitHub (pinned to b608633a7e)

Solutions

  1. Set the order rule type to one of ReportDataOrderRule::ATTR_TYPE_DIMENSION / ATTR_TYPE_METRIC / ATTR_TYPE_DIMENSION_FIELD when constructing the rule.
  2. Validate sort payloads at the controller boundary and reject unknown types with a 422-style response instead of letting them reach the builder.
  3. Update or reset saved dashboard definitions after upgrading so order rules use the current format.
  4. 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).

Example fix

// before
$orderRule = new ReportDataOrderRule;
$orderRule->setAttributeName('status'); // type never set

// after
$orderRule = new ReportDataOrderRule;
$orderRule->setDataAttributeType(ReportDataOrderRule::ATTR_TYPE_DIMENSION);
$orderRule->setAttributeName('status');
$orderRule->setIsAscending(true);
Defensive patterns

Strategy: validation

Validate before calling

$validOrderTypes = [
    ReportDataOrderRule::ATTR_TYPE_DIMENSION,
    ReportDataOrderRule::ATTR_TYPE_METRIC,
    ReportDataOrderRule::ATTR_TYPE_DIMENSION_FIELD,
];
$order = $payload['orderBy'] ?? null;
if ($order !== null) {
    $type = $order['attribute']['type'] ?? null;
    if (!in_array($type, $validOrderTypes, true)) {
        throw new InvalidArgumentException('Invalid order rule attribute type.');
    }
    // if ordering by metric, also confirm the code exists
    if ($type === ReportDataOrderRule::ATTR_TYPE_METRIC) {
        ReportMetric::findMetricByCodeStrict($metrics, $order['attribute']['name'], false)
            ?? throw new InvalidArgumentException('Unknown metric in order rule.');
    }
}

Type guard

function isValidOrderRuleType(mixed $type): bool
{
    return is_string($type) && in_array($type, [
        ReportDataOrderRule::ATTR_TYPE_DIMENSION,
        ReportDataOrderRule::ATTR_TYPE_METRIC,
        ReportDataOrderRule::ATTR_TYPE_DIMENSION_FIELD,
    ], true);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21). Data as JSON: /api/errors/fe11a329acbf2fb7. Report an issue: GitHub.