thanos-io/thanos · error · api.ApiError

zero or negative query resolution step widths are not…

Error message

zero or negative query resolution step widths are not accepted. Try a positive integer

What it means

In queryRange, after the step is resolved (from the `step` parameter or the default), a non-positive step is rejected with HTTP 400 (api.ErrorBadData). A zero or negative step would make point computation impossible, so the API requires a strictly positive duration. Note that parseStep's default of rangeSeconds/250 can itself round down to 0 for sub-second ranges, and an explicit `step=0` or negative value triggers this directly.

Solutions

  1. Pass an explicit positive step such as `step=1s` or `step=15s`.
  2. Validate step > 0 in the client before issuing the request.
  3. Widen the query range (or set an explicit step) so the default rangeSeconds/250 does not compute to 0.

Example fix

// before
GET /api/v1/query_range?query=up&start=...&end=...&step=0
// after
GET /api/v1/query_range?query=up&start=...&end=...&step=15s
Defensive patterns

Strategy: validation

Validate before calling

const stepMs = parseDurationMs(step); // e.g. '15s' -> 15000
if (step !== undefined && (!Number.isFinite(stepMs) || stepMs <= 0)) {
  throw new Error('step must be a positive duration');
}

Try / catch

const body = await res.json();
if (body.status === 'error' && /zero or negative query resolution step/.test(body.error)) {
  // retry with an explicit positive step such as 1s
}

Prevention

When it happens

Trigger: Calling /api/v1/query_range with `step=0`, `step=-1m`, or when the step parameter parses to a zero/negative duration; also with a very short range and no step, when the rangeSeconds/250 default computes to 0.

Common situations: Clients sending step from a variable that is empty or 0; users entering '0' in a dashboard step field; sub-second query ranges relying on the automatic 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/ec50035c59b12eae. Report an issue: GitHub.

Appendix: source

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

	if err != nil {
		return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}
	}
	end, err := parseTime(r.FormValue("end"))
	if err != nil {
		return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}, func() {}
	}
	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() {}
		}

View on GitHub (pinned to 35b8b99117)