vitessio/vitess · error

mismatched cutoff and label lengths

Error message

mismatched cutoff and label lengths

What it means

NewGenericHistogram requires the labels slice to be exactly one longer than the cutoffs slice: one label per cutoff bucket plus a final label that captures everything above the highest cutoff. The library panics immediately when the counts do not satisfy this invariant.

Source

Thrown at go/stats/histogram.go:61

// based on the cutoffs. The buckets are categorized using the
// following criterion: cutoff[i-1] < value <= cutoff[i]. Anything
// higher than the highest cutoff is labeled as "inf".
func NewHistogram(name, help string, cutoffs []int64) *Histogram {
	labels := make([]string, len(cutoffs)+1)
	for i, v := range cutoffs {
		labels[i] = strconv.FormatInt(v, 10)
	}
	labels[len(labels)-1] = "inf"
	return NewGenericHistogram(name, help, cutoffs, labels, "Count", "Total")
}

// NewGenericHistogram creates a histogram where all the labels are
// supplied by the caller. The number of labels has to be one more than
// the number of cutoffs because the last label captures everything that
// exceeds the highest cutoff.
func NewGenericHistogram(name, help string, cutoffs []int64, labels []string, countLabel, totalLabel string) *Histogram {
	if len(cutoffs) != len(labels)-1 {
		panic("mismatched cutoff and label lengths")
	}
	h := &Histogram{
		name:       name,
		help:       help,
		cutoffs:    cutoffs,
		labels:     labels,
		countLabel: countLabel,
		totalLabel: totalLabel,
		buckets:    make([]atomic.Int64, len(labels)),
	}
	if name != "" {
		publish(name, h)
	}
	return h
}

// Adds a hook that will be called every time a new value is added to the histogram
func (h *Histogram) AddHook(hook func(int64)) {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Make len(labels) == len(cutoffs)+1, with the last label the overflow bucket (commonly "unlimited").
  2. Recount the arrays at the call site; ensure every new cutoff gets a matching label plus keep the final catch-all label.
  3. Define cutoffs and labels together as a single paired constant/slice to avoid drift.

Example fix

// before
cutoffs := []int64{1, 10, 100}
labels := []string{"0-1", "1-10", "10-100"} // panics: missing catch-all
// after
labels := []string{"0-1", "1-10", "10-100", "unlimited"}
Defensive patterns

Strategy: validation

Validate before calling

if len(labels) != len(cutoffs)+1 {
    return fmt.Errorf("histogram %s: need %d labels, got %d", name, len(cutoffs)+1, len(labels))
}
h := stats.NewGenericHistogram(name, help, cutoffs, labels, countLabel, totalLabel)

Prevention

When it happens

Trigger: Calling stats.NewGenericHistogram(name, help, cutoffs, labels, ...) with len(cutoffs) != len(labels)-1, e.g. 4 cutoffs with 4 or 6 labels.

Common situations: Hand-editing a cutoffs list without updating labels; generating labels programmatically and off-by-one; copying a predefined label set but trimming the catch-all last label.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/f01032aaefa221cc. Report an issue: GitHub.