octobercms/october · error · SystemException
Unknown metric:
Error message
Unknown metric:
What it means
ReportMetric::findMetricByCodeStrict(array $availableMetrics, string $metricCode, bool $throw = true) looks up a metric by its unique code and, when not found and $throw is true, throws SystemException('Unknown metric: <code>'). Callers include Dash widget metric resolution, ReportDataSourceBase and ReportQueryBuilder (ordering by a metric). The error means the code string you referenced does not exist in the metric list the data source defines — usually a typo, a renamed code, or asking a data source for another source's metric.
Source
Thrown at modules/dashboard/classes/ReportMetric.php:216
if (!count($metric)) {
return null;
}
return end($metric);
}
/**
* Finds a metric by its code. Throws an exception if the metric is not found.
* @param ReportMetric[] $availableMetrics
* @param string $metricCode
* @param bool $throw Throw exception if the metric doesn't exist.
* @return ?ReportMetric
*/
public static function findMetricByCodeStrict(array $availableMetrics, string $metricCode, $throw = true): ?ReportMetric
{
$metric = self::findMetricByCode($availableMetrics, $metricCode);
if (!$metric && $throw) {
throw new SystemException('Unknown metric: '.$metricCode);
}
return $metric;
}
/**
* Returns code unique for this metric to be used as a part of a cache key.
* @return string
*/
public function getCacheUniqueCode(): string
{
return $this->getCode() . $this->getDatabaseColumnName() . $this->getAggregateFunction();
}
/**
* Returns a query column name corresponding to this metric.
* @return string
*/View on GitHub (pinned to b608633a7e)
Solutions
- Open the data source class (defineMetrics()/getAvailableMetrics()) and align the referenced code with an existing metric code exactly, including case.
- If the metric should exist, add it: new ReportMetric('total_revenue', ...) in the data source's metric list.
- If stale dashboard definitions are the cause, update or reset the saved dashboard/widget configuration (Dashboard model) so it references current codes.
- If absence is legitimate at runtime, call findMetricByCodeStrict($metrics, $code, false) to get null instead of an exception and handle it gracefully.
Example fix
// before
$metric = ReportMetric::findMetricByCodeStrict($dataSource->getAvailableMetrics(), 'total_revenue');
// after (metric code fixed to what the source defines)
$metric = ReportMetric::findMetricByCodeStrict($dataSource->getAvailableMetrics(), 'revenue');
// after (tolerate absence)
$metric = ReportMetric::findMetricByCodeStrict($dataSource->getAvailableMetrics(), 'total_revenue', false);
if (!$metric) { /* skip or default */ } Defensive patterns
Strategy: validation
Validate before calling
$metrics = $dataSource->getAvailableMetrics();
$known = array_map(fn(ReportMetric $m) => $m->getCode(), $metrics);
if (!in_array($metricCode, $known, true)) {
// fix the code, or skip, or fail with a clear message
throw new InvalidArgumentException("Unknown metric '{$metricCode}'. Known: " . implode(', ', $known));
}
$metric = ReportMetric::findMetricByCodeStrict($metrics, $metricCode); Type guard
function metricExists(array $availableMetrics, string $code): bool
{
foreach ($availableMetrics as $metric) {
if ($metric instanceof ReportMetric && $metric->getCode() === $code) {
return true;
}
}
return false;
} Try / catch
try {
$metric = ReportMetric::findMetricByCodeStrict($metrics, $metricCode);
} catch (SystemException $e) {
// log and degrade instead of a 500 on stale dashboard configs
Log::warning($e->getMessage());
$metric = null;
} Prevention
- Treat metric codes as stable public API: never rename them without migrating stored dashboard definitions.
- Expose the list of valid metric codes to the front-end so UIs only offer selectable codes.
- Use findMetricByCodeStrict(..., false) when absence is a normal, handleable case.
When it happens
Trigger: A dashboard/widget request or definition references metric code 'total_revenue' while the data source defines 'revenue'; ordering report data by a metric attribute whose code was never added via defineMetrics(); calling findMetricByCodeStrict($metrics, $code) where $metrics came from a different data source than the code belongs to.
Common situations: Renaming a metric code in a data source while stale dashboard definitions (stored per-user or in DB) still reference the old code; copy-pasting a widget config between data sources; case mismatch ('Revenue' vs 'revenue') — codes are case-sensitive because findMetricByCode compares getCode() === $metricCode.
Related errors
- The database column name cannot be empty.
- The display name cannot be empty.
- The aggregate function cannot be empty.
- The aggregate function is not supported:
- Trying to get selected row without a popup reference.
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/b4bdeb2b173c6a52.
Report an issue: GitHub.