{"record":{"id":"b0bf4493f23fc916","repo":"thanos-io/thanos","slug":"parse-block-label-matchers","errorCode":null,"errorMessage":"parse block label matchers","messagePattern":"parse block label matchers","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/thanos/tools_bucket.go","lineNumber":770,"sourceCode":"func registerBucketReplicate(app extkingpin.AppClause, objStoreConfig *extflag.PathOrContent) {\n\tcmd := 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))\n\thttpBindAddr, httpGracePeriod, httpTLSConfig := extkingpin.RegisterHTTPFlags(cmd)\n\ttoObjStoreConfig := extkingpin.RegisterCommonObjStoreFlags(cmd, \"-to\", false, \"The object storage which replicate data to.\")\n\n\ttbc := &bucketReplicateConfig{}\n\ttbc.registerBucketReplicateFlag(cmd)\n\n\tminTime := 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.\").\n\t\tDefault(\"0000-01-01T00:00:00Z\"))\n\tmaxTime := 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.\").\n\t\tDefault(\"9999-12-31T23:59:59Z\"))\n\tids := 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()\n\tignoreMarkedForDeletion := cmd.Flag(\"ignore-marked-for-deletion\", \"Do not replicate blocks that have deletion mark.\").Bool()\n\n\tcmd.Setup(func(g *run.Group, logger log.Logger, reg *prometheus.Registry, tracer opentracing.Tracer, _ <-chan struct{}, _ bool) error {\n\t\tmatchers, err := replicate.ParseFlagMatchers(tbc.matcherStrs)\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"parse block label matchers\")\n\t\t}\n\n\t\tvar resolutionLevels []compact.ResolutionLevel\n\t\tfor _, lvl := range tbc.resolutions {\n\t\t\tresolutionLevels = append(resolutionLevels, compact.ResolutionLevel(lvl.Milliseconds()))\n\t\t}\n\n\t\tif len(tbc.compactions) == 0 {\n\t\t\tif tbc.compactMin > tbc.compactMax {\n\t\t\t\treturn errors.New(\"compaction-min must be less than or equal to compaction-max\")\n\t\t\t}\n\t\t\ttbc.compactions = []int{}\n\t\t\tfor compactionLevel := tbc.compactMin; compactionLevel <= tbc.compactMax; compactionLevel++ {\n\t\t\t\ttbc.compactions = append(tbc.compactions, compactionLevel)\n\t\t\t}\n\t\t}\n\n\t\tblockIDs := make([]ulid.ULID, 0, len(*ids))","sourceCodeStart":752,"sourceCodeEnd":788,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/cmd/thanos/tools_bucket.go#L752-L788","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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\"."],"exampleFix":"// before\n--match=block_labels=set=whole\n// after\n--match='block_labels=\"set=whole\"'","handlingStrategy":"validation","validationCode":"for _, m := range matcherStrs {\n    ms, err := parser.ParseMetricSelector(\"{\" + m + \"}\")\n    if err != nil {\n        return fmt.Errorf(\"--match value %q is not a valid matcher: %w\", m, err)\n    }\n    _ = ms\n}","typeGuard":null,"tryCatchPattern":"if err := replicateCmd.RunE(cmd, args); err != nil {\n    if strings.Contains(err.Error(), \"parse block label matchers\") {\n        fmt.Fprintln(os.Stderr, \"--match must look like: --match='block_labels=\\\"set=whole\\\"'\")\n    }\n}","preventionTips":["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"],"tags":["cli","label-matchers","flag-parsing"],"backgroundTag":"invalid-cli-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"}