{"record":{"id":"3a599144a404744c","repo":"apache/beam","slug":"metric-name-s-being-reused-for-a-different-metric-type-in-a","errorCode":null,"errorMessage":"metric name %s being reused for a different metric type in a single PTransform","messagePattern":"metric name (.+?) being reused for a different metric type in a single PTransform","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/metrics/store.go","lineNumber":244,"sourceCode":"\n\ttransitions *int64\n\tbundleState *BundleState\n}\n\nfunc newStore() *Store {\n\treturn &Store{store: make(map[Labels]userMetric), stateRegistry: make(map[string]*[4]ExecutionState), transitions: new(int64), bundleState: &BundleState{}}\n}\n\n// storeMetric stores a metric away on its first use so it may be retrieved later on.\n// In the event of a name collision, storeMetric can panic, so it's prudent to release\n// locks if they are no longer required.\nfunc (b *Store) storeMetric(pid string, n name, m userMetric) {\n\tb.mu.Lock()\n\tdefer b.mu.Unlock()\n\tl := Labels{transform: pid, namespace: n.namespace, name: n.name}\n\tif ms, ok := b.store[l]; ok {\n\t\tif ms.kind() != m.kind() {\n\t\t\tpanic(fmt.Sprintf(\"metric name %s being reused for a different metric type in a single PTransform\", n))\n\t\t}\n\t\treturn\n\t}\n\tb.store[l] = m\n}\n\n// BundleState returns the bundle state.\nfunc (b *Store) BundleState() string {\n\tbs := *(*BundleState)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&b.bundleState))))\n\treturn bs.String()\n}\n\n// StateRegistry returns the state registry that stores bundleID to executions states mapping.\nfunc (b *Store) StateRegistry() string {\n\tb.mu.Lock()\n\tdefer b.mu.Unlock()\n\tbuilder := &strings.Builder{}\n\tbuilder.WriteString(\"\\n | All Bundle Process States | \\n\")","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/metrics/store.go#L226-L262","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rename one of the conflicting metrics so each name maps to exactly one kind per transform.","Move one of the metrics into a different namespace.","Keep metric kind consistent per name across the codebase (e.g. a metrics registry/constant list)."],"exampleFix":"// before\n NewCounter(ns, \"records\"), NewDistribution(ns, \"records\") // panic\n// after\nNewCounter(ns, \"records\"), NewDistribution(ns, \"records_values\")","handlingStrategy":"validation","validationCode":"if seen[kindOf(m)] {\n\treturn fmt.Errorf(\"metric %s.%s already registered as a different kind\", ns, name)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a central registry mapping metric name to kind and reuse it everywhere.","Never change a metric's kind without renaming it.","In shared libraries, prefix metric names with the library namespace to avoid collisions."],"tags":["go","panic","beam","metrics","conflict"],"backgroundTag":"internal-invariant-violation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}