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

  1. Open the data source class (defineMetrics()/getAvailableMetrics()) and align the referenced code with an existing metric code exactly, including case.
  2. If the metric should exist, add it: new ReportMetric('total_revenue', ...) in the data source's metric list.
  3. If stale dashboard definitions are the cause, update or reset the saved dashboard/widget configuration (Dashboard model) so it references current codes.
  4. 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

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


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