temporalio/temporal · error

not implemented

Error message

not implemented

What it means

priMetricHandler wraps the matching service's metrics handler to dual-record priority metrics. WithTags is intentionally unimplemented: the wrapper expects tags to be applied via the underlying handler methods (Counter/Histogram/Gauge return recorders that accept tags per call), so a WithTags call indicates a misuse of the handler API.

Source

Thrown at service/matching/pri_metrics_handler.go:67

}

func (p priMetricHandler) Stop(logger log.Logger) {
	p.handler.Stop(logger)
}

func (p priMetricHandler) Counter(name string) metrics.CounterIface {
	return priMetricsCounter{name: name, handler: p.handler}
}
func (p priMetricHandler) Timer(name string) metrics.TimerIface {
	return priMetricsTimer{name: name, handler: p.handler}
}

func (p priMetricHandler) Gauge(name string) metrics.GaugeIface {
	return priMetricsGauge{name: name, handler: p.handler}
}

func (p priMetricHandler) WithTags(...metrics.Tag) metrics.Handler {
	panic("not implemented")
}

func (p priMetricHandler) Histogram(string, metrics.MetricUnit) metrics.HistogramIface {
	panic("not implemented")
}

func (p priMetricHandler) StartBatch(string) metrics.BatchHandler {
	panic("not implemented")
}

func (c priMetricsCounter) Record(i int64, tag ...metrics.Tag) {
	c.handler.Counter(c.name).Record(i, tag...)
	c.handler.Counter(withPriPrefix(c.name)).Record(i, tag...)
}

func (t priMetricsTimer) Record(duration time.Duration, tag ...metrics.Tag) {
	t.handler.Timer(t.name).Record(duration, tag...)
	t.handler.Timer(withPriPrefix(t.name)).Record(duration, tag...)

View on GitHub (pinned to bde624efd1)

Solutions

  1. Do not call WithTags on priMetricHandler; pass tags per-record via the recorder methods (Counter(name).Record(v, tag...))
  2. If tags are required at handler level, implement WithTags to return a tag-applying wrapper over p.handler instead of panicking
  3. Use the embedded underlying handler (p.handler) when generic handler behavior is needed

Example fix

// before
h := p.priHandler // priMetricHandler
h.WithTags(metrics.StringTag("queue", qName)).Counter("foo").Record(1)

// after
h := p.handler // underlying metrics.Handler
h.WithTags(metrics.StringTag("queue", qName)).Counter("foo").Record(1)
Defensive patterns

Strategy: validation

Validate before calling

// Never call WithTags on the pri wrapper; resolve the base handler first
if h, ok := handler.(metrics.Handler); ok && isPriMetricHandler(h) {
	return fmt.Errorf("use underlying handler for WithTags")
}

Try / catch

func safeWithTags(h metrics.Handler, tags ...metrics.Tag) (scoped metrics.Handler, err error) {
	defer func() {
		if rec := recover(); rec != nil {
			err = fmt.Errorf("WithTags unsupported: %v", rec)
		}
	}()
	return h.WithTags(tags...), nil
}

Prevention

When it happens

Trigger: Any code calling WithTags on a priMetricHandler — e.g. passing the wrapper where a generic metrics.Handler is expected and generic instrumentation code invokes WithTags to attach routing/scheduling tags.

Common situations: Refactors that thread a metrics.Handler through shared code without knowing the pri/fair wrappers only support the subset of the interface; new metric emissions added inside priority-task-queue code paths.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/a12cf53fa1d04c4b. Report an issue: GitHub.