thanos-io/thanos · error · ApiError
invalid metric metadata limit=
Error message
invalid metric metadata limit='%v'
What it means
The metric metadata handler parses the `limit` query param with ParseInt base 10 bitsize 32; if that fails it reports the raw string as an invalid limit. Note the message prints the parsed (zero) limit, not the input string, because on error `limit` is 0.
Solutions
- Pass a plain integer that fits in int32 (0 to 2147483647), e.g. ?limit=100.
- Validate with strconv.ParseInt(s, 10, 32) before the request.
- Omit the limit parameter to use the server default.
Example fix
// before GET /api/v1/metadata?limit=99999999999 // after GET /api/v1/metadata?limit=100
Defensive patterns
Strategy: validation
Validate before calling
function validMetadataLimit(s) {
if (!/^-?\d+$/.test(s)) return false;
return BigInt(s) >= -2147483648n && BigInt(s) <= 2147483647n;
} Prevention
- Keep limits within int32 range (max 2147483647).
- Prefer modest limits (100–10000) — metadata responses are large.
- Validate all query params against the endpoint's expected types in the client SDK.
When it happens
Trigger: GET /api/v1/metadata?limit=abc, limit=99999999999 (>int32), or limit=1.5 hitting the QueryAPI metadata handler.
Common situations: Oversized limits exceeding int32 max (2147483647); non-numeric placeholders from UIs; SDKs forwarding raw strings from user config.
Understand the failure class
Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.
Related errors
- cannot parse to a valid limit
- limit must be non-negative
- cannot parse to a valid duration. It overflows int64
- cannot parse to a valid duration
- could not sync metas
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/b51e1afbb3ba1e29.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/api/query/v1.go:1672
var (
t map[string][]metadatapb.Meta
warnings annotations.Annotations
err error
)
req := &metadatapb.MetricMetadataRequest{
// By default we use -1, which means no limit.
Limit: -1,
Metric: r.URL.Query().Get("metric"),
PartialResponseStrategy: ps,
}
limitStr := r.URL.Query().Get("limit")
if limitStr != "" {
limit, err := strconv.ParseInt(limitStr, 10, 32)
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("invalid metric metadata limit='%v'", limit)}, func() {}
}
req.Limit = int32(limit)
}
tracing.DoInSpan(ctx, "retrieve_metadata", func(ctx context.Context) {
t, warnings, err = client.MetricMetadata(ctx, req)
})
if err != nil {
return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "retrieving metadata")}, func() {}
}
return t, warnings.AsErrors(), nil, func() {}
}
}
func (qapi *QueryAPI) tsdbStatus(r *http.Request) (any, []error, *api.ApiError, func()) {
span, ctx := tracing.StartSpan(r.Context(), "tsdb_statistics_query_request")
defer span.Finish()View on GitHub (pinned to 35b8b99117)