octobercms/october · error · SystemException
The aggregate function is not supported:
Error message
The aggregate function is not supported:
What it means
After the empty-string checks, the ReportMetric constructor validates $aggregateFunction against a fixed whitelist: sum, avg, min, max, count, none, count_distinct, count_distinct_not_null (the AGGREGATE_* constants). Any other non-empty string throws SystemException with the offending value appended. This is the enforcement point for the closed set of SQL aggregates the report query builder knows how to render; there is no extension mechanism here, so custom functions cannot be registered.
Source
Thrown at modules/dashboard/classes/ReportMetric.php:93
}
if (!strlen($aggregateFunction)) {
throw new SystemException('The aggregate function cannot be empty.');
}
$knownAggregateFunctions = [
self::AGGREGATE_SUM,
self::AGGREGATE_AVG,
self::AGGREGATE_MIN,
self::AGGREGATE_MAX,
self::AGGREGATE_COUNT,
self::AGGREGATE_NONE,
self::AGGREGATE_COUNT_DISTINCT,
self::AGGREGATE_COUNT_DISTINCT_NOT_NULL
];
if (!in_array($aggregateFunction, $knownAggregateFunctions)) {
throw new SystemException('The aggregate function is not supported: ' . $aggregateFunction);
}
$this->code = $code;
$this->databaseColumnName = $databaseColumnName;
$this->displayName = $displayName;
$this->aggregateFunction = $aggregateFunction;
$this->intlFormatOptions = $intlFormatOptions;
}
/**
* Returns the metric code.
* @return string Returns the metric code.
*/
public function getCode(): string
{
return $this->code;
}
View on GitHub (pinned to b608633a7e)
Solutions
- Use the class constants: ReportMetric::AGGREGATE_SUM, AGGREGATE_AVG, AGGREGATE_MIN, AGGREGATE_MAX, AGGREGATE_COUNT, AGGREGATE_NONE, AGGREGATE_COUNT_DISTINCT, AGGREGATE_COUNT_DISTINCT_NOT_NULL.
- Normalize incoming config values: strtolower + str_replace(' ', '_', ...) mapped to the constants before constructing.
- If you need COUNT(DISTINCT col), use AGGREGATE_COUNT_DISTINCT — the column goes in the databaseColumnName argument, not the function string.
- If you truly need an unsupported aggregate, compute it in the data source query/view and expose the result with AGGREGATE_NONE.
Example fix
// before
new ReportMetric('customers', 'customer_id', 'Customers', 'distinct_count');
// after
new ReportMetric('customers', 'customer_id', 'Customers', ReportMetric::AGGREGATE_COUNT_DISTINCT); Defensive patterns
Strategy: validation
Validate before calling
const AGGREGATES = [
ReportMetric::AGGREGATE_SUM, ReportMetric::AGGREGATE_AVG,
ReportMetric::AGGREGATE_MIN, ReportMetric::AGGREGATE_MAX,
ReportMetric::AGGREGATE_COUNT, ReportMetric::AGGREGATE_NONE,
ReportMetric::AGGREGATE_COUNT_DISTINCT, ReportMetric::AGGREGATE_COUNT_DISTINCT_NOT_NULL,
];
function normalizeAggregate(string $raw): string {
$map = ['distinct_count' => 'count_distinct', 'countdistinct' => 'count_distinct'];
$fn = $map[strtolower(trim($raw))] ?? strtolower(trim($raw));
if (!in_array($fn, AGGREGATES, true)) {
throw new InvalidArgumentException("Unsupported aggregate function: {$raw}");
}
return $fn;
} Type guard
function isValidAggregate(string $fn): bool
{
return in_array($fn, [
ReportMetric::AGGREGATE_SUM, ReportMetric::AGGREGATE_AVG,
ReportMetric::AGGREGATE_MIN, ReportMetric::AGGREGATE_MAX,
ReportMetric::AGGREGATE_COUNT, ReportMetric::AGGREGATE_NONE,
ReportMetric::AGGREGATE_COUNT_DISTINCT, ReportMetric::AGGREGATE_COUNT_DISTINCT_NOT_NULL,
], true);
} Prevention
- Reference AGGREGATE_* constants only; they are the single source of truth.
- Normalize external aggregate names (API/UI payloads) to the constants at the boundary.
- Watch for COUNT DISTINCT needs: use AGGREGATE_COUNT_DISTINCT rather than composing SQL text.
When it happens
Trigger: Passing a raw SQL-ish string like 'COUNT(DISTINCT x)', 'SUM', 'Average', 'distinct_count', or a typo like 'cont' as the 4th constructor argument. Case matters: the constants are lowercase, so 'SUM' fails in_array without strict comparison only by luck — stick to constants.
Common situations: Copy-pasting SQL into the metric definition; using a hypothetical constant name that does not exist; mapping a REST/UI payload field with different naming ('countDistinct' vs 'count_distinct') straight into the constructor.
Related errors
- The aggregate function cannot be empty.
- The database column name cannot be empty.
- The display name cannot be empty.
- Unknown metric:
- Invalid aggregate function:
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/cefa348c73f75120.
Report an issue: GitHub.