{"record":{"id":"bd622d42d28845de","repo":"thanos-io/thanos","slug":"penalty-based-deduplication-needs-at-least-one-rep","errorCode":null,"errorMessage":"penalty based deduplication needs at least one replica label specified","messagePattern":"penalty based deduplication needs at least one replica label specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/thanos/compact.go","lineNumber":334,"sourceCode":"\t\tlevel.Warn(logger).Log(\"msg\", \"Max compaction level is lower than should be\", \"current\", conf.maxCompactionLevel, \"default\", compactions.maxLevel())\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tctx = tracing.ContextWithTracer(ctx, tracer)\n\n\tdefer func() {\n\t\tif rerr != nil {\n\t\t\tcancel()\n\t\t}\n\t}()\n\n\tvar mergeFunc storage.VerticalChunkSeriesMergeFunc\n\tswitch conf.dedupFunc {\n\tcase compact.DedupAlgorithmPenalty:\n\t\tmergeFunc = dedup.NewChunkSeriesMerger()\n\n\t\tif len(dedupReplicaLabels) == 0 {\n\t\t\treturn errors.New(\"penalty based deduplication needs at least one replica label specified\")\n\t\t}\n\tcase \"\":\n\t\tmergeFunc = storage.NewCompactingChunkSeriesMerger(storage.ChainedSeriesMerge)\n\n\tdefault:\n\t\treturn errors.Errorf(\"unsupported deduplication func, got %s\", conf.dedupFunc)\n\t}\n\n\t// Instantiate the compactor with different time slices. Timestamps in TSDB\n\t// are in milliseconds.\n\tcomp, err := tsdb.NewLeveledCompactor(ctx, reg, logutil.GoKitLogToSlog(logger), levels, downsample.NewPool(), mergeFunc)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"create compactor\")\n\t}\n\n\tvar (\n\t\tcompactDir      = path.Join(conf.dataDir, \"compact\")\n\t\tdownsamplingDir = path.Join(conf.dataDir, \"downsample\")","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/cmd/thanos/compact.go#L316-L352","documentation":"Penalty-based deduplication (DedupAlgorithmPenalty) merges series by penalizing replicas, which requires replica labels to distinguish sources. runCompact rejects the combination of --deduplication.penalty with no --deduplication.replica-label flags via this plain errors.New.","triggerScenarios":"Starting compact with --deduplication.func=penalty while --deduplication.replica-label is unset or empty.","commonSituations":"Operators enabling penalty dedup for multi-replica setups but forgetting to declare which labels distinguish replicas (e.g. replica, prometheus).","solutions":["Add at least one --deduplication.replica-label=<label> when using penalty dedup.","Switch to the default dedup func by removing --deduplication.func=penalty if replica labels aren't available.","Verify the replica label actually exists in your Prometheus external labels."],"exampleFix":"// before\nthanos compact --deduplication.func=penalty ...\n// after\nthanos compact --deduplication.func=penalty --deduplication.replica-label=replica ...","handlingStrategy":"validation","validationCode":"if dedupFunc == \"penalty\" && len(dedupReplicaLabels) == 0 {\n    return fmt.Errorf(\"--deduplication.func=penalty requires at least one --deduplication.replica-label\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair --deduplication.func=penalty with --deduplication.replica-label","Confirm the replica label exists in Prometheus external_labels","Encode the dependency in your helm/kustomize templates so flags ship together"],"tags":["config","deduplication","cli"],"backgroundTag":"missing-required-argument","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"}