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

  1. Ensure every custom metric is registered through the module/extension API (metrics.NewCounter/NewGauge/etc.) before any sample with that name is emitted
  2. Re-run with K6_WEB_DASHBOARD=false to confirm the test itself is healthy and isolate the problem to the dashboard path
  3. Rebuild extensions against the same k6 version as the binary to eliminate schema skew
  4. 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

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


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/5ff75382e110adb4. Report an issue: GitHub.