thanos-io/thanos · error · api.ApiError

exceeded maximum resolution of 11,000 points per…

Error message

exceeded maximum resolution of 11,000 points per timeseries. Try decreasing the query resolution (?step=XX)

What it means

The Thanos Query API's range endpoint refuses to serve a query that would return more than 11,000 points per timeseries (end-start)/step > 11000. This is a safety limit to protect the querier from exhausting memory/CPU on huge range queries. It is returned wrapped in an ApiError of type ErrorBadData (HTTP 400).

Solutions

  1. Increase the step parameter (e.g. ?step=3600 for 1h resolution) so (end-start)/step <= 11000
  2. Shrink the time range by setting a narrower start/end window
  3. Split one large query into several smaller queries and merge client-side

Example fix

// before
GET /api/v1/query_range?query=up&start=2024-01-01T00:00:00Z&end=2024-03-01T00:00:00Z&step=60s
// after
GET /api/v1/query_range?query=up&start=2024-01-01T00:00:00Z&end=2024-03-01T00:00:00Z&step=600s
Defensive patterns

Strategy: validation

Validate before calling

if end.Sub(start)/step > 11000 {
    step = end.Sub(start) / 11000 // round up to a safe step before calling the API
}

Prevention

When it happens

Trigger: Calling the /api/v1/query_range endpoint where (end - start) / step exceeds 11000, e.g. start=now-90d, end=now with default step, or omitting step so a too-small default is used.

Common situations: Dashboarding tools (Grafana) requesting very long time ranges with 1m or smaller steps; ad-hoc curl queries over weeks of data at sub-minute resolution; after a version change that lowered the default step.

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


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

Appendix: source

Thrown at pkg/api/query/v1.go:795

	if end.Before(start) {
		err := errors.New("end timestamp must not be before start time")
		return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}
	}

	step, apiErr := qapi.parseStep(r, qapi.defaultRangeQueryStep, int64(end.Sub(start)/time.Second))
	if apiErr != nil {
		return nil, nil, apiErr, func() {}
	}

	if step <= 0 {
		err := errors.New("zero or negative query resolution step widths are not accepted. Try a positive integer")
		return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}
	}

	// For safety, limit the number of returned points per timeseries.
	// This is sufficient for 60s resolution for a week or 1h resolution for a year.
	if end.Sub(start)/step > 11000 {
		err := errors.New("exceeded maximum resolution of 11,000 points per timeseries. Try decreasing the query resolution (?step=XX)")
		return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}
	}

	ctx := r.Context()
	if to := r.FormValue("timeout"); to != "" {
		var cancel context.CancelFunc
		timeout, err := parseDuration(to)
		if err != nil {
			return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}
		}

		ctx, cancel = context.WithTimeout(ctx, timeout)
		defer cancel()
	}

	enableDedup, apiErr := qapi.parseEnableDedupParam(r)
	if apiErr != nil {
		return nil, nil, apiErr, func() {}

View on GitHub (pinned to 35b8b99117)