argoproj/argo-workflows · error
found existing gauge for custom metric %s of type %s
Error message
found existing gauge for custom metric %s of type %s
What it means
A custom Prometheus metric name already exists but is registered as an OpenTelemetry Float64ObservableGauge, while the new spec requests a different metric type (and is not realtime, which is gauge-compatible). OpenTelemetry instruments cannot change type under the same name, so the mismatch is rejected.
Source
Thrown at workflow/metrics/metrics_custom.go:150
// CustomMetricExists returns if metric exists from its key
// This is exported for testing only
func (m *Metrics) CustomMetricExists(key string) bool {
return m.GetCustomMetric(key) != nil
}
// TODO labels on custom metrics
func (m *Metrics) matchExistingMetric(metricSpec *wfv1.Prometheus) (*telemetry.Instrument, error) {
key := metricSpec.Name
if inst := m.GetInstrument(key); inst != nil {
if inst.GetDescription() != metricSpec.Help {
return nil, fmt.Errorf("help for metric %s is already set to %s, it cannot be changed", metricSpec.Name, inst.GetDescription())
}
wantedType := metricSpec.GetMetricType()
switch inst.GetOtel().(type) {
case *metric.Float64ObservableGauge:
if wantedType != wfv1.MetricTypeGauge && !metricSpec.IsRealtime() {
return nil, fmt.Errorf("found existing gauge for custom metric %s of type %s", metricSpec.Name, wantedType)
}
case *metric.Float64ObservableCounter:
if wantedType != wfv1.MetricTypeCounter {
return nil, fmt.Errorf("found existing counter for custom metric %s of type %s", metricSpec.Name, wantedType)
}
case *metric.Float64Histogram:
if wantedType != wfv1.MetricTypeHistogram {
return nil, fmt.Errorf("found existing histogram for custom metric %s of type %s", metricSpec.Name, wantedType)
}
default:
return nil, fmt.Errorf("found unwanted type %s for custom metric %s of type %s", reflect.TypeOf(inst.GetOtel()), metricSpec.Name, wantedType)
}
return inst, nil
}
return nil, nil
}
func (m *Metrics) ensureBaseMetric(metricSpec *wfv1.Prometheus, ownerKey string) (*telemetry.Instrument, error) {View on GitHub (pinned to 35bff19146)
Solutions
- Use a unique metric name per type, or align all declarations to the same type
- Keep `realtime: true` if you must reuse the gauge name with realtime semantics, or drop realtime and use consistent Gauge specs
- Make base-metric upgrades (e.g. changing built-in metric types) explicit by using a new metric name
- Validate the spec with `argo lint` before submitting
Example fix
// before - name: duration kind: Gauge - name: duration kind: Histogram # type clash // after - name: duration kind: Gauge - name: duration_hist kind: Histogram
Defensive patterns
Strategy: validation
Validate before calling
kindByName := map[string]wfv1.MetricType{}
for _, m := range spec.Prometheus {
if t, seen := kindByName[m.Name]; seen && t != m.GetMetricType() && !m.IsRealtime() {
return fmt.Errorf("metric %s declared as %v and %v", m.Name, t, m.GetMetricType())
}
kindByName[m.Name] = m.GetMetricType()
} Try / catch
if err != nil && strings.Contains(err.Error(), "found existing gauge") {
// rename one of the metrics or unify kinds, then resubmit
} Prevention
- Keep one metric type per metric name for the whole workflow lifetime
- Don't change metric kinds between a step and its retry
- Remember realtime metrics are gauges — dropping `realtime: true` can surface this conflict
- Lint specs before submitting
When it happens
Trigger: Workflow spec declares the same metric name twice with different `kind`/type (e.g. first `Gauge`, later `Histogram`, `Counter`, or `Distribution`), or a retry redeclares a gauge metric as a counter.
Common situations: Editing a metric's type between a step and its retry; two templates emitting a same-named metric with different types; changing `realtime: true` off so the gauge exemption no longer applies.
Related errors
- help for metric %s is already set to %s, it cannot be change
- found existing counter for custom metric %s of type %s
- found existing histogram for custom metric %s of type %s
- found unwanted type %s for custom metric %s of type %s
- failed to create new metric %s
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/bdcd35fe93a48db0.
Report an issue: GitHub.