thanos-io/thanos · error

unrecognized label

Error message

unrecognized label %q

What it means

parseFlagLabels parses repeated label CLI flags of the form name=value into a labels.Labels set. This error is returned when an entry contains no '=' separator after SplitN(l, "=", 2), so it cannot be interpreted as a key/value pair. Thanos throws it to fail fast on malformed label arguments rather than silently dropping them.

Solutions

  1. Add the '=' separator: pass --label key=value (quote the whole flag value if the shell splits it).
  2. Check shell quoting: use --label 'key="value"' so '=' and quotes survive argument splitting.
  3. Inspect the offending label text shown in %q and re-run with the corrected entry.

Example fix

// before
thanos sidecar --label owner --label cluster=eu1
// after
thanos sidecar --label owner=platform --label cluster=eu1
Defensive patterns

Strategy: validation

Validate before calling

func validLabelArg(l string) bool { return strings.Contains(l, "=") && strings.SplitN(l, "=", 2)[0] != "" }

Try / catch

// Go: check err from parseFlagLabels/main startup
if err := parseFlagLabels(flagLabels); err != nil {
    return fmt.Errorf("bad --label flag %q: %w", flagLabels, err)
}

Prevention

When it happens

Trigger: Calling parseFlagLabels (directly in tests, or via flag parsing of e.g. --label in main) with a string lacking '=', such as "--label owner" instead of "--label owner=team-a".

Common situations: Users pass a bare label name without a value on the command line; shell quoting/escaping drops the '='; copying docs examples with missing separator; YAML/Compose env passing truncating arguments.

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


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/ac9ac07ddee071b8. Report an issue: GitHub.

Appendix: source

Thrown at cmd/thanos/config.go:332

	cmd.Flag("alertmanagers.send-timeout", "Timeout for sending alerts to Alertmanager").Default("10s").
		DurationVar(&ac.alertmgrsTimeout)
	cmd.Flag("alertmanagers.sd-dns-interval", "Interval between DNS resolutions of Alertmanager hosts.").
		Default("30s").DurationVar(&ac.alertmgrsDNSSDInterval)
	ac.alertQueryURL = cmd.Flag("alert.query-url", "The external Thanos Query URL that would be set in all alerts 'Source' field").String()
	cmd.Flag("alert.label-drop", "Labels by name to drop before sending to alertmanager. This allows alert to be deduplicated on replica label (repeated). Similar Prometheus alert relabelling").
		StringsVar(&ac.alertExcludeLabels)
	ac.alertRelabelConfigPath = extflag.RegisterPathOrContent(cmd, "alert.relabel-config", "YAML file that contains alert relabelling configuration.", extflag.WithEnvSubstitution())
	ac.alertSourceTemplate = cmd.Flag("alert.query-template", "Template to use in alerts source field. Need only include {{.Expr}} parameter").Default("/graph?g0.expr={{.Expr}}&g0.tab=1").String()

	return ac
}

func parseFlagLabels(s []string) (labels.Labels, error) {
	var lset labels.ScratchBuilder
	for _, l := range s {
		parts := strings.SplitN(l, "=", 2)
		if len(parts) != 2 {
			return labels.EmptyLabels(), errors.Errorf("unrecognized label %q", l)
		}
		if !model.UTF8Validation.IsValidLabelName(parts[0]) {
			return labels.EmptyLabels(), errors.Errorf("unsupported format for label %s", l)
		}
		val, err := strconv.Unquote(parts[1])
		if err != nil {
			return labels.EmptyLabels(), errors.Wrap(err, "unquote label value")
		}
		lset.Add(parts[0], val)
	}
	lset.Sort()
	return lset.Labels(), nil
}

type goMemLimitConfig struct {
	enableAutoGoMemlimit bool
	memlimitRatio        float64
}

View on GitHub (pinned to 35b8b99117)