{"record":{"id":"dcb9ade801f4f1c0","repo":"thanos-io/thanos","slug":"non-unique-name-for-metric-family-q","errorCode":null,"errorMessage":"non-unique name for metric family: %q","messagePattern":"non-unique name for metric family: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cortex/util/metrics_helper.go","lineNumber":80,"sourceCode":"\n// MetricFamilyMap is a map of metric names to their family (metrics with same name, but different labels)\n// Keeping map of metric name to its family makes it easier to do searches later.\ntype MetricFamilyMap map[string]*dto.MetricFamily\n\n// NewMetricFamilyMap sorts output from Gatherer.Gather method into a map.\n// Gatherer.Gather specifies that there metric families are uniquely named, and we use that fact here.\n// If they are not, this method returns error.\nfunc NewMetricFamilyMap(metrics []*dto.MetricFamily) (MetricFamilyMap, error) {\n\tperMetricName := MetricFamilyMap{}\n\n\tfor _, m := range metrics {\n\t\tname := m.GetName()\n\t\t// these errors should never happen when passing Gatherer.Gather() output.\n\t\tif name == \"\" {\n\t\t\treturn nil, errors.New(\"empty name for metric family\")\n\t\t}\n\t\tif perMetricName[name] != nil {\n\t\t\treturn nil, fmt.Errorf(\"non-unique name for metric family: %q\", name)\n\t\t}\n\n\t\tperMetricName[name] = m\n\t}\n\n\treturn perMetricName, nil\n}\n\nfunc (mfm MetricFamilyMap) SumCounters(name string) float64 {\n\treturn sum(mfm[name], counterValue)\n}\n\nfunc (mfm MetricFamilyMap) SumGauges(name string) float64 {\n\treturn sum(mfm[name], gaugeValue)\n}\n\nfunc (mfm MetricFamilyMap) MaxGauges(name string) float64 {\n\treturn max(mfm[name], gaugeValue)","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/internal/cortex/util/metrics_helper.go#L62-L98","documentation":"NewMetricFamilyMap requires metric family names to be unique; a duplicate name in the input slice means the gatherer produced two families for the same metric, which violates the Prometheus data model. The helper fails fast with the offending name in the message.","triggerScenarios":"A []*dto.MetricFamily passed to NewMetricFamilyMap (via softRemoveUserRegistry or BuildMetricFamiliesPerUser) where two entries share the same GetName() value — usually a collector that emits one family per sample instead of aggregating.","commonSituations":"Custom collectors that call NewMetricFamily or send per-sample families instead of grouping by metric name; client_golang bugs where the same metric is registered under multiple collectors; dynamically re-registered collectors racing with Gather().","solutions":["Find the collector emitting duplicate family names (the error message quotes the name) and make it aggregate all samples into a single MetricFamily.","Ensure each metric name is registered by exactly one collector in the registry.","Deduplicate the input slice by name before calling NewMetricFamilyMap if you control its construction.","Pin/upgrade client_golang to a version where Gather guarantees unique families."],"exampleFix":"// before\nfor _, mf := range raw {\n    out = append(out, mf) // may contain duplicate names\n}\n// after\nseen := map[string]bool{}\nfor _, mf := range raw {\n    if !seen[mf.GetName()] {\n        seen[mf.GetName()] = true\n        out = append(out, mf)\n    }\n}","handlingStrategy":"validation","validationCode":"names := map[string]int{}\nfor _, mf := range families {\n    names[mf.GetName()]++\n}\nfor n, c := range names {\n    if c > 1 { return fmt.Errorf(\"collector emits duplicate family %q\", n) }\n}","typeGuard":null,"tryCatchPattern":"mfm, err := util.NewMetricFamilyMap(metrics)\nif err != nil {\n    level.Error(logger).Log(\"msg\", \"duplicate metric family\", \"err\", err)\n    return nil, err\n}","preventionTips":["Register each metric name under exactly one collector.","Aggregate samples per family inside Collect before emitting.","Bisect collectors to find the duplicate emitter when the quoted name is known."],"tags":["metrics","prometheus","duplicate"],"backgroundTag":"internal-invariant-violation","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}