thanos-io/thanos · error
parse block label matchers
Error message
parse block label matchers
What it means
The `bucket replicate` command parses --match (matcherStrs) via replicate.ParseFlagMatchers, which requires each flag value to be a valid Prometheus label matcher of the form key="value" or key=~"regex". This error wraps the parse failure, so at least one matcher string is malformed.
Solutions
- Quote the whole flag value so inner quotes survive: --match='block_labels="set=whole"'.
- Validate any regex in =~ matchers with a regex tester (balanced delimiters, no dangling + or *).
- Check the wrapped inner error — it names the first matcher that failed.
- Verify syntax against Prometheus matcher format: key="val", key!="val", key=~"re", key!~"re".
Example fix
// before --match=block_labels=set=whole // after --match='block_labels="set=whole"'
Defensive patterns
Strategy: validation
Validate before calling
for _, m := range matcherStrs {
ms, err := parser.ParseMetricSelector("{" + m + "}")
if err != nil {
return fmt.Errorf("--match value %q is not a valid matcher: %w", m, err)
}
_ = ms
} Try / catch
if err := replicateCmd.RunE(cmd, args); err != nil {
if strings.Contains(err.Error(), "parse block label matchers") {
fmt.Fprintln(os.Stderr, "--match must look like: --match='block_labels=\"set=whole\"'")
}
} Prevention
- Single-quote matchers in shell so inner double quotes survive
- Test any =~ regexes separately before embedding in the flag
- Follow Prometheus matcher syntax: key="v", key!="v", key=~"re", key!~"re"
- List existing block labels with `thanos tools bucket inspect` to match real label names
When it happens
Trigger: Running `thanos tools bucket replicate` with --match values that fail to parse as label matchers — missing quotes, invalid regex in =~ matchers, empty label name — at cmd/thanos/tools_bucket.go:770.
Common situations: Shell quoting issues removing inner double quotes (--match=block_labels="set=whole"), invalid regex like '--match=l=~"[unclosed"', or using --selector-style relabel syntax where matchers are expected.
Understand the failure class
Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.
Related errors
- error parsing selector flag
- level is bigger then default set of
- unknown sync strategy
- get compaction levels
- penalty based deduplication needs at least one replica…
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/b0bf4493f23fc916.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/thanos/tools_bucket.go:770
func registerBucketReplicate(app extkingpin.AppClause, objStoreConfig *extflag.PathOrContent) {
cmd := app.Command("replicate", fmt.Sprintf("Replicate data from one object storage to another. NOTE: Currently it works only with Thanos blocks (%v has to have Thanos metadata).", block.MetaFilename))
httpBindAddr, httpGracePeriod, httpTLSConfig := extkingpin.RegisterHTTPFlags(cmd)
toObjStoreConfig := extkingpin.RegisterCommonObjStoreFlags(cmd, "-to", false, "The object storage which replicate data to.")
tbc := &bucketReplicateConfig{}
tbc.registerBucketReplicateFlag(cmd)
minTime := model.TimeOrDuration(cmd.Flag("min-time", "Start of time range limit to replicate. Thanos Replicate will replicate only metrics, which happened later 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("0000-01-01T00:00:00Z"))
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))View on GitHub (pinned to 35b8b99117)