jaegertracing/jaeger · error

multiple backend types found for metric storage: %v

Error message

multiple backend types found for metric storage: %v

What it means

Same one-backend-per-definition rule as the trace variant, applied to metric storage: MetricBackend.Validate() gathers all populated backend types and rejects any metric backend entry that specifies more than one, returning this error with the list of types found.

Source

Thrown at cmd/internal/storageconfig/config.go:178

func (cfg *MetricBackend) Validate() error {
	var backends []string
	if cfg.Prometheus != nil {
		backends = append(backends, "prometheus")
	}
	if cfg.Elasticsearch != nil {
		backends = append(backends, "elasticsearch")
	}
	if cfg.Opensearch != nil {
		backends = append(backends, "opensearch")
	}
	if cfg.ClickHouse != nil {
		backends = append(backends, "clickhouse")
	}
	if len(backends) == 0 {
		return errors.New("empty configuration")
	}
	if len(backends) > 1 {
		return fmt.Errorf("multiple backend types found for metric storage: %v", backends)
	}
	return nil
}

// Validate validates the storage configuration.
func (c *Config) Validate() error {
	if len(c.TraceBackends) == 0 {
		return errors.New("at least one storage backend is required")
	}
	for name, b := range c.TraceBackends {
		if err := b.Validate(); err != nil {
			return fmt.Errorf("trace storage '%s': %w", name, err)
		}
	}
	for name, b := range c.MetricBackends {
		if err := b.Validate(); err != nil {
			return fmt.Errorf("metric storage '%s': %w", name, err)
		}

View on GitHub (pinned to 806f444784)

Solutions

  1. Keep exactly one backend type field inside each named metric backend entry; remove the extra
  2. Define separate named metric backends if you genuinely want multiple types available, then reference one per role
  3. Use the %v list in the error to identify which two types collided and which config keys to delete
  4. Audit generated/merged config (print the effective YAML) before starting Jaeger

Example fix

// before (config.yaml)
jaeger:
  storage:
    metric_backends:
      metrics:
        prometheus:
          host: "http://prom:9090"
        clickhouse:
          address: clickhouse:9000
// after
jaeger:
  storage:
    metric_backends:
      metrics:
        prometheus:
          host: "http://prom:9090"
Defensive patterns

Strategy: validation

Validate before calling

var cfg storageconfig.Config
if err := v.Unmarshal(&cfg); err != nil { return err }
for name, b := range cfg.MetricBackends {
    types := 0
    for _, set := range []interface{}{b.Prometheus, b.ClickHouse} {
        if !reflect.ValueOf(set).IsNil() { types++ }
    }
    if types > 1 {
        return fmt.Errorf("metric backend %q sets %d storage types; keep exactly one", name, types)
    }
}

Try / catch

if err := cfg.Validate(); err != nil {
    if strings.Contains(err.Error(), "multiple backend types found for metric storage") {
        // fix the named metric_backends entry named in the message
    }
    return err
}

Prevention

When it happens

Trigger: Calling Config.Validate() with a MetricBackends entry that has two or more backend fields populated, e.g. both `prometheus:` (remote storage config) and `clickhouse:` set on the same named metric backend.

Common situations: Config merge/Helm values layering that adds a second metric backend type to an existing entry; example configs combined by hand; leftovers of a migration from one metrics backend to another.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/c5862baaa162c862. Report an issue: GitHub.