thanos-io/thanos · error

empty name for metric family

Error message

empty name for metric family

What it means

NewMetricFamilyMap builds a map from dto.MetricFamily pointers keyed by family name. Prometheus's Gather() output must never contain a family with an empty name; if it does, the helper refuses to build the map and returns this error as an internal invariant violation.

Solutions

  1. Audit registered Collectors for Collect methods that append MetricFamily values without setting Name.
  2. Identify the offending collector by testing with only standard collectors enabled and bisecting.
  3. Ensure metrics come from Gatherer.Gather() output rather than manually constructed slices.
  4. Upgrade Prometheus client_golang / collector libraries to a version fixing the empty-name bug.
Defensive patterns

Strategy: validation

Validate before calling

for _, mf := range families {
    if mf.GetName() == "" {
        return fmt.Errorf("metric family with empty name from collector")
    }
}
err := util.NewMetricFamilyMap(families)

Try / catch

mfm, err := util.NewMetricFamilyMap(metrics)
if err != nil {
    level.Error(logger).Log("msg", "gather produced invalid metric families", "err", err)
    return nil, err
}

Prevention

When it happens

Trigger: Passing a []*dto.MetricFamily containing an entry whose GetName() is empty to NewMetricFamilyMap — typically via softRemoveUserRegistry or BuildMetricFamiliesPerUser on a registry whose gatherer produced a nameless family.

Common situations: Buggy custom collectors registering metrics without names; corrupt or hand-assembled MetricFamily slices; third-party collector implementations violating the prometheus contract.

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 thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/ca97eee5d16433c6. Report an issue: GitHub.

Appendix: source

Thrown at internal/cortex/util/metrics_helper.go:77

		out <- prometheus.MustNewConstMetric(desc, valueType, cr.Value, cr.LabelValues...)
	}
}

// MetricFamilyMap is a map of metric names to their family (metrics with same name, but different labels)
// Keeping map of metric name to its family makes it easier to do searches later.
type MetricFamilyMap map[string]*dto.MetricFamily

// NewMetricFamilyMap sorts output from Gatherer.Gather method into a map.
// Gatherer.Gather specifies that there metric families are uniquely named, and we use that fact here.
// If they are not, this method returns error.
func NewMetricFamilyMap(metrics []*dto.MetricFamily) (MetricFamilyMap, error) {
	perMetricName := MetricFamilyMap{}

	for _, m := range metrics {
		name := m.GetName()
		// these errors should never happen when passing Gatherer.Gather() output.
		if name == "" {
			return nil, errors.New("empty name for metric family")
		}
		if perMetricName[name] != nil {
			return nil, fmt.Errorf("non-unique name for metric family: %q", name)
		}

		perMetricName[name] = m
	}

	return perMetricName, nil
}

func (mfm MetricFamilyMap) SumCounters(name string) float64 {
	return sum(mfm[name], counterValue)
}

func (mfm MetricFamilyMap) SumGauges(name string) float64 {
	return sum(mfm[name], gaugeValue)
}

View on GitHub (pinned to 35b8b99117)