thanos-io/thanos · error
compaction-min must be less than or equal to compaction-max
Error message
compaction-min must be less than or equal to compaction-max
What it means
The replicate command derives compaction levels from --compaction-min and --compaction-max (when --compactions is not given). It explicitly rejects a configuration where min exceeds max with this error, because the generated level range would be empty/inverted.
Solutions
- Swap the values so compaction-min <= compaction-max (valid levels: 0, 1, 2).
- Alternatively pass an explicit --compactions list (e.g. --compactions=0,1) and the min/max check is skipped.
- Review automation scripts that compute min/max and enforce ordering before invoking the command.
Example fix
// before thanos tools bucket replicate ... --compaction-min=2 --compaction-max=1 // after thanos tools bucket replicate ... --compaction-min=1 --compaction-max=2
Defensive patterns
Strategy: validation
Validate before calling
if compactionMin > compactionMax {
return errors.New("--compaction-min must be <= --compaction-max (valid levels: 0,1,2)")
} Try / catch
if err := replicateCmd.Execute(); err != nil {
if strings.Contains(err.Error(), "compaction-min must be less than or equal") {
os.Exit(2) // fix flag ordering and retry
}
} Prevention
- Remember valid compaction levels are 0, 1, 2
- Pass an explicit --compactions list to bypass min/max entirely
- In scripts, sort min/max before composing the command line
- Double-check flag order when hand-typing long commands
When it happens
Trigger: Running `thanos tools bucket replicate` with --compaction-min greater than --compaction-max (e.g. min=3 max=1) and no explicit --compactions list — cmd/thanos/tools_bucket.go:780.
Common situations: Users swapping the two flags on the command line or scripting where the values are computed in the wrong order; also confusion between compaction levels (0,1,2) and time ranges.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- unsupported format for label
- --auto-gomemlimit.ratio must be greater than 0 and less…
- error validating the config
- --receive.lazy-retrieval-max-buffered-responses must be > 0
- Address is duplicated for --query flag.
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/ed7842be1b5bbba5.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/thanos/tools_bucket.go:780
maxTime := model.TimeOrDuration(cmd.Flag("max-time", "End of time range limit to replicate. Thanos Replicate will replicate only metrics, which happened earlier than this value. Option can be a constant time in RFC3339 format or time duration relative to current time, such as -1d or 2h45m. Valid duration units are ms, s, m, h, d, w, y.").
Default("9999-12-31T23:59:59Z"))
ids := cmd.Flag("id", "Block to be replicated to the destination bucket. IDs will be used to match blocks and other matchers will be ignored. When specified, this command will be run only once after successful replication. Repeated field").Strings()
ignoreMarkedForDeletion := cmd.Flag("ignore-marked-for-deletion", "Do not replicate blocks that have deletion mark.").Bool()
cmd.Setup(func(g *run.Group, logger log.Logger, reg *prometheus.Registry, tracer opentracing.Tracer, _ <-chan struct{}, _ bool) error {
matchers, err := replicate.ParseFlagMatchers(tbc.matcherStrs)
if err != nil {
return errors.Wrap(err, "parse block label matchers")
}
var resolutionLevels []compact.ResolutionLevel
for _, lvl := range tbc.resolutions {
resolutionLevels = append(resolutionLevels, compact.ResolutionLevel(lvl.Milliseconds()))
}
if len(tbc.compactions) == 0 {
if tbc.compactMin > tbc.compactMax {
return errors.New("compaction-min must be less than or equal to compaction-max")
}
tbc.compactions = []int{}
for compactionLevel := tbc.compactMin; compactionLevel <= tbc.compactMax; compactionLevel++ {
tbc.compactions = append(tbc.compactions, compactionLevel)
}
}
blockIDs := make([]ulid.ULID, 0, len(*ids))
for _, id := range *ids {
bid, err := ulid.Parse(id)
if err != nil {
return errors.Wrap(err, "invalid ULID found in --id flag")
}
blockIDs = append(blockIDs, bid)
}
return replicate.RunReplicate(
g,View on GitHub (pinned to 35b8b99117)