apache/beam · error

metric name %s being reused for a different metric type in a

Error message

metric name %s being reused for a different metric type in a single PTransform

What it means

The metric Store indexes user metrics per PTransform by labels (transform, namespace, name). If the same metric name is registered twice within one PTransform but with a different metric kind (counter vs distribution vs gauge), the store cannot represent both, so it panics to preserve the internal invariant.

Source

Thrown at sdks/go/pkg/beam/core/metrics/store.go:244

	transitions *int64
	bundleState *BundleState
}

func newStore() *Store {
	return &Store{store: make(map[Labels]userMetric), stateRegistry: make(map[string]*[4]ExecutionState), transitions: new(int64), bundleState: &BundleState{}}
}

// storeMetric stores a metric away on its first use so it may be retrieved later on.
// In the event of a name collision, storeMetric can panic, so it's prudent to release
// locks if they are no longer required.
func (b *Store) storeMetric(pid string, n name, m userMetric) {
	b.mu.Lock()
	defer b.mu.Unlock()
	l := Labels{transform: pid, namespace: n.namespace, name: n.name}
	if ms, ok := b.store[l]; ok {
		if ms.kind() != m.kind() {
			panic(fmt.Sprintf("metric name %s being reused for a different metric type in a single PTransform", n))
		}
		return
	}
	b.store[l] = m
}

// BundleState returns the bundle state.
func (b *Store) BundleState() string {
	bs := *(*BundleState)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&b.bundleState))))
	return bs.String()
}

// StateRegistry returns the state registry that stores bundleID to executions states mapping.
func (b *Store) StateRegistry() string {
	b.mu.Lock()
	defer b.mu.Unlock()
	builder := &strings.Builder{}
	builder.WriteString("\n | All Bundle Process States | \n")

View on GitHub (pinned to 12126d8942)

Solutions

  1. Rename one of the conflicting metrics so each name maps to exactly one kind per transform.
  2. Move one of the metrics into a different namespace.
  3. Keep metric kind consistent per name across the codebase (e.g. a metrics registry/constant list).

Example fix

// before
 NewCounter(ns, "records"), NewDistribution(ns, "records") // panic
// after
NewCounter(ns, "records"), NewDistribution(ns, "records_values")
Defensive patterns

Strategy: validation

Validate before calling

if seen[kindOf(m)] {
	return fmt.Errorf("metric %s.%s already registered as a different kind", ns, name)
}

Prevention

When it happens

Trigger: Within a single PTransform, calling e.g. metrics.NewCounter(ns, "x") and metrics.NewDistribution(ns, "x") (or gauge) with the same namespace/name — the second storeMetric call finds an existing entry whose kind differs.

Common situations: Refactoring a metric's type without renaming it, two libraries used in one transform coincidentally sharing a metric name, or copy-pasting metric declarations and changing only the constructor kind.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/3a599144a404744c. Report an issue: GitHub.