thanos-io/thanos · error

label set contains duplicate label names

Error message

label set contains duplicate label names

What it means

ErrDuplicateLabels is a sentinel error signaling that a label set contains two labels with the same name. The capnproto writer detects it when validating labels: consecutive sorted label names compare equal (cmp == 0), so the write is rejected because duplicate names make the series ambiguous.

Solutions

  1. Deduplicate labels by name before writing (merge external labels with labels.Labels.Range/labels.New).
  2. On the sending side, use relabeling to drop duplicate labels rather than appending raw.
  3. In custom writers, use labels.Builder which rejects/overwrites duplicates.

Example fix

// before
lbls := labels.FromStrings("env", "prod", "env", "dev") // duplicate
// after
b := labels.NewBuilder(labels.EmptyLabels())
b.Set("env", "prod") // last-wins, no duplicates
Defensive patterns

Strategy: validation

Validate before calling

func hasDuplicateLabels(lbls labels.Labels) error {
	var prev string
	dup := false
	lbls.Range(func(l labels.Label) error {
		if l.Name == prev { dup = true }
		prev = l.Name
		return nil
	})
	if dup { return errors.New("duplicate label names") }
	return nil
}

Type guard

func isDuplicateLabelsErr(err error) bool { return errors.Is(err, labelpb.ErrDuplicateLabels) }

Try / catch

if err := writer.Write(ctx, series); err != nil {
	if errors.Is(err, labelpb.ErrDuplicateLabels) {
		series.Labels = dedupe(series.Labels) // last-wins merge
		return writer.Write(ctx, series)
	}
	return err
}

Prevention

When it happens

Trigger: Writing a TimeSeries whose labels list contains the same name twice (e.g. two 'env' labels) via pkg/receive/capnproto_writer.go, or when custom client code appends external labels without first merging with existing ones.

Common situations: Client libraries that append external/target labels without deduplicating; multi-tenant proxies injecting labels already present in the payload; hand-constructed labels.Labels from unsorted, duplicated name/value pairs.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/9b7f73f947fa6e91. Report an issue: GitHub.

Appendix: source

Thrown at pkg/store/labelpb/label.go:28

	"encoding/json"
	"fmt"
	"io"
	"sort"
	"strings"
	"sync"
	"unique"
	"unsafe"

	"github.com/VictoriaMetrics/easyproto"
	"github.com/cespare/xxhash/v2"
	"github.com/pkg/errors"
	"github.com/prometheus/prometheus/model/labels"
)

var (
	ErrOutOfOrderLabels = errors.New("out of order labels")
	ErrEmptyLabels      = errors.New("label set contains a label with empty name or value")
	ErrDuplicateLabels  = errors.New("label set contains duplicate label names")

	sep = []byte{'\xff'}
)

func noAllocString(buf []byte) string {
	return *(*string)(unsafe.Pointer(&buf))
}

func noAllocBytes(buf string) []byte {
	return *(*[]byte)(unsafe.Pointer(&buf))
}

// ZLabelsFromPromLabels converts Prometheus labels to slice of labelpb.ZLabel in type unsafe manner.
// It reuses the same memory. Caller should abort using passed labels.Labels.
func ZLabelsFromPromLabels(lset labels.Labels) []ZLabel {
	return *(*[]ZLabel)(unsafe.Pointer(&lset))
}

View on GitHub (pinned to 35b8b99117)