tsenart/vegeta · error
failed to register metric %v: %w
Error message
failed to register metric %v: %w
What it means
Returned when one of the prometheus collectors (latency histogram, bytes-in/out counters, fail counter) cannot be registered with the provided prometheus.Registerer. Prometheus rejects duplicate registrations of the same metric name, so a second Register call on the same registry fails.
Source
Thrown at lib/prom/prom.go:57
Help: "Bytes sent to servers during requests",
}, baseLabels),
requestFailCounter: prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "request_fail_count",
Help: "Count of failed requests",
}, append(baseLabels[:len(baseLabels):len(baseLabels)], "message")),
}
}
// Register registers all Prometheus metrics in r.
func (pm *Metrics) Register(r prometheus.Registerer) error {
for _, c := range []prometheus.Collector{
pm.requestLatencyHistogram,
pm.requestBytesInCounter,
pm.requestBytesOutCounter,
pm.requestFailCounter,
} {
if err := r.Register(c); err != nil {
return fmt.Errorf("failed to register metric %v: %w", c, err)
}
}
return nil
}
// Observe metrics given a vegeta.Result.
func (pm *Metrics) Observe(res *vegeta.Result) {
code := strconv.FormatUint(uint64(res.Code), 10)
pm.requestBytesInCounter.WithLabelValues(res.Method, res.URL, code).Add(float64(res.BytesIn))
pm.requestBytesOutCounter.WithLabelValues(res.Method, res.URL, code).Add(float64(res.BytesOut))
pm.requestLatencyHistogram.WithLabelValues(res.Method, res.URL, code).Observe(res.Latency.Seconds())
if res.Error != "" {
pm.requestFailCounter.WithLabelValues(res.Method, res.URL, code, res.Error)
}
}
// NewHandler returns a new http.Handler that exposes Prometheus
// metrics registed in r in the OpenMetrics format.View on GitHub (pinned to cf58112690)
Solutions
- Use prometheus.NewRegistry() per attack or component instead of the default global registry.
- Call the Unregister (or a wrapped MustUnregister) before re-Registering the same collectors.
- Guard registration with promauto or check AlreadyRegisteredError before Registering.
- Upgrade vegeta if you hit duplicate-name collisions between its built-in collectors and your own.
Example fix
// before
reg := prometheus.DefaultRegisterer
if err := prom.Register(reg); err != nil { return err }
// after
reg := prometheus.NewRegistry()
if err := prom.Register(reg); err != nil { return err } Defensive patterns
Strategy: try-catch
Validate before calling
// Check for existing registration before registering vegeta metrics
func safeRegister(r prometheus.Registerer, c prometheus.Collector) error {
if err := r.Register(c); err != nil {
var are prometheus.AlreadyRegisteredError
if errors.As(err, &are) {
return nil // already registered, reuse
}
return err
}
return nil
} Type guard
func isAlreadyRegistered(err error) bool {
var are prometheus.AlreadyRegisteredError
return errors.As(err, &are)
} Try / catch
if err := prom.Register(reg); err != nil {
var are prometheus.AlreadyRegisteredError
if errors.As(err, &are) {
return nil // safe to ignore: metric exists
}
return fmt.Errorf("metric registration failed: %w", err)
} Prevention
- Use a fresh prometheus.NewRegistry() per attack instead of DefaultRegisterer.
- Unregister collectors before re-registration on config reload.
- Register metrics once at startup, not per request/attack.
When it happens
Trigger: Calling prom.Registerer's Register (e.g. via attack metric registration) twice on the same prometheus.Registry, or the same registry already containing metrics with identical names.
Common situations: Registering vegeta attack metrics into prometheus.DefaultRegisterer in a long-running process, then re-registering (e.g. on config reload or a second attack); hot-reloading metrics without deregistering.
Related errors
- error registering prometheus metrics: %s
- point with sequence number %d in %v
- bad target: %s
- bad method: %s
- bad URL: %s, %w
AI-assisted analysis of tsenart/vegeta@cf58112690 (2026-08-31).
Data as JSON: /api/errors/a1498ab7cc5c7498.
Report an issue: GitHub.