{"record":{"id":"9b7f73f947fa6e91","repo":"thanos-io/thanos","slug":"label-set-contains-duplicate-label-names","errorCode":null,"errorMessage":"label set contains duplicate label names","messagePattern":"label set contains duplicate label names","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/store/labelpb/label.go","lineNumber":28,"sourceCode":"\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"unique\"\n\t\"unsafe\"\n\n\t\"github.com/VictoriaMetrics/easyproto\"\n\t\"github.com/cespare/xxhash/v2\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/prometheus/prometheus/model/labels\"\n)\n\nvar (\n\tErrOutOfOrderLabels = errors.New(\"out of order labels\")\n\tErrEmptyLabels      = errors.New(\"label set contains a label with empty name or value\")\n\tErrDuplicateLabels  = errors.New(\"label set contains duplicate label names\")\n\n\tsep = []byte{'\\xff'}\n)\n\nfunc noAllocString(buf []byte) string {\n\treturn *(*string)(unsafe.Pointer(&buf))\n}\n\nfunc noAllocBytes(buf string) []byte {\n\treturn *(*[]byte)(unsafe.Pointer(&buf))\n}\n\n// ZLabelsFromPromLabels converts Prometheus labels to slice of labelpb.ZLabel in type unsafe manner.\n// It reuses the same memory. Caller should abort using passed labels.Labels.\nfunc ZLabelsFromPromLabels(lset labels.Labels) []ZLabel {\n\treturn *(*[]ZLabel)(unsafe.Pointer(&lset))\n}\n","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/store/labelpb/label.go#L10-L46","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Deduplicate labels by name before writing (merge external labels with labels.Labels.Range/labels.New).","On the sending side, use relabeling to drop duplicate labels rather than appending raw.","In custom writers, use labels.Builder which rejects/overwrites duplicates."],"exampleFix":"// before\nlbls := labels.FromStrings(\"env\", \"prod\", \"env\", \"dev\") // duplicate\n// after\nb := labels.NewBuilder(labels.EmptyLabels())\nb.Set(\"env\", \"prod\") // last-wins, no duplicates","handlingStrategy":"validation","validationCode":"func hasDuplicateLabels(lbls labels.Labels) error {\n\tvar prev string\n\tdup := false\n\tlbls.Range(func(l labels.Label) error {\n\t\tif l.Name == prev { dup = true }\n\t\tprev = l.Name\n\t\treturn nil\n\t})\n\tif dup { return errors.New(\"duplicate label names\") }\n\treturn nil\n}","typeGuard":"func isDuplicateLabelsErr(err error) bool { return errors.Is(err, labelpb.ErrDuplicateLabels) }","tryCatchPattern":"if err := writer.Write(ctx, series); err != nil {\n\tif errors.Is(err, labelpb.ErrDuplicateLabels) {\n\t\tseries.Labels = dedupe(series.Labels) // last-wins merge\n\t\treturn writer.Write(ctx, series)\n\t}\n\treturn err\n}","preventionTips":["Merge external labels via labels.Builder instead of appending raw.","Dedupe label maps before constructing labels.Labels.","When proxying writes between tenants, check for injected-label collisions."],"tags":["labels","validation","remote-write"],"backgroundTag":"invalid-argument-format","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"}