thanos-io/thanos · error

error enforcing label

Error message

error enforcing label

What it means

EnforceQueryTenancy wraps failures from the injectproxy PromQL enforcer's EnforceNode with this message. The query parsed successfully, but injecting the tenancy label matcher into the expression failed — some AST nodes cannot have the tenant label matcher added (e.g. unsupported expression shapes or selectors the enforcer cannot rewrite).

Solutions

  1. Inspect the wrapped inner error from EnforceNode for the specific unsupported node
  2. Simplify the query (avoid exotic constructs) or split it into supported expressions
  3. Upgrade Thanos/prom-label-proxy to a version supporting the query constructs used
  4. Ensure queries contain at least one vector selector the tenant matcher can be injected into

Example fix

// before (construct enforcer cannot rewrite)
sort_desc(rate(some_metric[5m] offset 1w))
// after
rate(some_metric[5m])
Defensive patterns

Strategy: try-catch

Try / catch

// Go
rewritten, err := EnforceQueryTenancy(query, tenant, enforce)
if err != nil && strings.Contains(err.Error(), "error enforcing label") {
    return "", fmt.Errorf("query not enforceable for tenancy: %w", errors.Unwrap(err))
}

Prevention

When it happens

Trigger: EnforceQueryTenancy receives a syntactically valid query whose AST contains nodes the prom-label-proxy enforcer refuses, so e.EnforceNode(expr) returns an error.

Common situations: Advanced PromQL (nested subqueries, exotic function usage) not supported by the bundled enforcer version; version skew between Thanos and its prom-label-proxy dependency; queries without any selector the matcher can attach to.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at pkg/tenancy/tenancy.go:158

	return md.Get(DefaultTenantHeader)[0], true
}

func EnforceQueryTenancy(tenantLabel string, tenant string, query string) (string, error) {
	labelMatcher := &labels.Matcher{
		Name:  tenantLabel,
		Type:  labels.MatchEqual,
		Value: tenant,
	}

	e := injectproxy.NewPromQLEnforcer(false, labelMatcher)

	expr, err := extpromql.ParseExpr(query)
	if err != nil {
		return "", errors.Wrap(err, "error parsing query string, when enforcing tenenacy")
	}

	if err := e.EnforceNode(expr); err != nil {
		return "", errors.Wrap(err, "error enforcing label")
	}

	return expr.String(), nil
}

func getLabelMatchers(formMatchers []string, tenant string, enforceTenancy bool, tenantLabel string) ([][]*labels.Matcher, error) {
	tenantLabelMatcher := &labels.Matcher{
		Name:  tenantLabel,
		Type:  labels.MatchEqual,
		Value: tenant,
	}

	matcherSets := make([][]*labels.Matcher, 0, len(formMatchers))

	// If tenancy is enforced, but there are no matchers at all, add the tenant matcher
	if len(formMatchers) == 0 && enforceTenancy {
		var matcher []*labels.Matcher
		matcher = append(matcher, tenantLabelMatcher)

View on GitHub (pinned to 35b8b99117)