grafana/k6 · error
unknown metric: %s
Error message
unknown metric: %s
What it means
The web dashboard output consumes the JSON sample stream and resolves each sample's 'metric' field by name in a registry built from ingested metric definitions. processPoint returns the errUnknownMetric sentinel wrapped with the metric name when a sample references a metric the registry does not contain — meaning the sample stream and the metric registry are out of sync (samples emitted for a metric that was never defined, or a stream/registry mismatch).
Source
Thrown at internal/dashboard/aggregate.go:246
thresholds := make([]string, 0, len(tres))
for _, res := range tres {
thresholds = append(thresholds, res.String())
}
_, err = agg.registry.getOrNew(name, metricType, valueType, thresholds)
return err
}
func (agg *aggregator) processPoint(data []byte) error {
timestamp := gjson.GetBytes(data, "data.time").Time()
name := gjson.GetBytes(data, "metric").String()
metric := agg.registry.Get(name)
if metric == nil {
return fmt.Errorf("%w: %s", errUnknownMetric, name)
}
tags := agg.tagSetFrom(gjson.GetBytes(data, "data.tags"))
sample := metrics.Sample{ //nolint:exhaustruct
Time: timestamp,
Value: gjson.GetBytes(data, "data.value").Float(),
TimeSeries: metrics.TimeSeries{ //nolint:exhaustruct
Metric: metric,
Tags: tags,
},
}
container := metrics.ConnectedSamples{ //nolint:exhaustruct
Samples: []metrics.Sample{sample},
Time: sample.Time,
Tags: tags,
}View on GitHub (pinned to 93accf6570)
Solutions
- Ensure every custom metric is registered through the module/extension API (metrics.NewCounter/NewGauge/etc.) before any sample with that name is emitted
- Re-run with K6_WEB_DASHBOARD=false to confirm the test itself is healthy and isolate the problem to the dashboard path
- Rebuild extensions against the same k6 version as the binary to eliminate schema skew
- If it occurs with a stock output, report it at https://github.com/grafana/k6/issues with the script and versions
Example fix
// before (extension emits an unregistered metric name)
samples.push({ metric: 'my_ext_requests', ... });
// after (register the metric in the module's registry at init, reuse the handle)
const reqCounter = metrics.NewCounter('my_ext_requests'); // registered via New().Metrics
samples.push({ metric: reqCounter.Name, ... }); Defensive patterns
Strategy: validation
Validate before calling
// In an extension: register every metric before emitting, and never hardcode names at emit time
// func New() *Module { m.Metrics["my_ext_requests"] = metrics.NewCounter("my_ext_requests") }
if _, ok := m.Metrics["my_ext_requests"]; !ok {
return fmt.Errorf("metric my_ext_requests not registered")
}
// Quick isolation when the error appears:
# K6_WEB_DASHBOARD=false k6 run script.js # confirms the run itself is healthy Prevention
- Register all custom metrics via the module API before the first sample is emitted
- Rebuild extensions against the same k6 version as the core
- Define metric names as constants shared by registration and emission
- Report stock-output occurrences upstream with script and versions
When it happens
Trigger: Running with the dashboard enabled (K6_WEB_DASHBOARD=true or --web-dashboard) while an extension or custom output emits samples whose metric name was never registered via the metrics registry that the aggregator ingested; version skew between an extension and the k6 core changing the sample schema.
Common situations: Extensions emitting custom metrics without registering them first; feeding externally produced JSON streams into a mismatched dashboard build; regressions after upgrading k6 or an xk6 extension.
Related errors
- Unexpected end of selector while parsing selector `${selecto
- invalid duration
- metrics must be declared in the init context
- parsing metric name failed
- invalid metric type
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/5ff75382e110adb4.
Report an issue: GitHub.