thanos-io/thanos · error · ApiError
invalid label name
Error message
invalid label name: %q
What it means
The label values endpoint validates the label name from the URL path against Prometheus' model.UTF8Validation.IsValidLabelName rules and returns ErrorBadData (HTTP 400) if it fails. Label names must match the Prometheus label-name syntax (legacy [a-zA-Z_][a-zA-Z0-9_]* or UTF-8 quoted form).
Solutions
- Use a label name matching the legacy pattern ^[a-zA-Z_][a-zA-Z0-9_]*$
- If using UTF-8 label names, ensure the client quotes/escapes them per the UTF-8 naming scheme and the server supports it
- URL-encode the label name correctly in the path
Example fix
// before GET /api/v1/label/my.label/values // after GET /api/v1/label/my_label/values
Defensive patterns
Strategy: validation
Validate before calling
func validLegacyLabelName(s string) bool {
if s == "" { return false }
for i, r := range s {
ok := r == '_' || (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (i > 0 && r >= '0' && r <= '9')
if !ok { return false }
}
return true
} Prevention
- Reuse prometheus/model/labels validation client-side instead of hand-rolling patterns
- URL-encode label names placed in the path
- For UTF-8 label names, verify server version supports them and quote per spec
When it happens
Trigger: GET /api/v1/label/<name>/values with a name containing invalid characters (dots, dashes, spaces, empty name), or a UTF-8 name sent unquoted to an endpoint expecting legacy validation.
Common situations: Typos in dashboard label selectors; querying metric-name-like strings with slashes; newer UTF-8 label names used against tooling that doesn't quote them.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- unsupported format for label
- ULID is not valid
- negative ' ' is not accepted. Try a positive integer
- results truncated due to limit
- split queries interval should be greater than 0 when…
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/b27eccf42d351776.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/api/query/v1.go:1080
// Optional stats field in response if parameter "stats" is not empty.
var qs stats.QueryStats
if r.FormValue(Stats) != "" {
qs = stats.NewQueryStats(qry.Stats())
}
return &queryData{
ResultType: res.Value.Type(),
Result: res.Value,
Stats: qs,
QueryAnalysis: analysis,
}, warnings, nil, qry.Close
}
func (qapi *QueryAPI) labelValues(r *http.Request) (any, []error, *api.ApiError, func()) {
ctx := r.Context()
name := route.Param(ctx, "name")
if !model.UTF8Validation.IsValidLabelName(name) {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("invalid label name: %q", name)}, func() {}
}
start, end, err := parseMetadataTimeRange(r, qapi.defaultMetadataTimeRange)
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}
}
enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse)
if apiErr != nil {
return nil, nil, apiErr, func() {}
}
storeDebugMatchers, apiErr := qapi.parseStoreDebugMatchersParam(r)
if apiErr != nil {
return nil, nil, apiErr, func() {}
}
limit, err := parseLimitParam(r.FormValue("limit"))View on GitHub (pinned to 35b8b99117)