Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Grafana By James Joyner IV · · 8 min read

Grafana Error Guide: 'interval must be greater than 0' — Fix Panel and Variable Intervals

Quick answer

Fix Grafana 'interval must be greater than 0' panel errors: correct min interval and interval variables, fix $__interval, and resolve zero-step queries.

  • #grafana
  • #observability
  • #troubleshooting
  • #errors
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

Grafana (or its datasource backend) raises this when a query’s step/interval resolves to zero or a non-positive duration, so the time-series engine can’t build a range vector. The panel shows:

interval must be greater than 0

Prometheus-backed variants of the same underlying problem read:

invalid parameter "step": zero or negative query resolution step widths are not accepted
error parsing range query: interval 0s is not valid

In every case the computed step — from $__interval, $__rate_interval, a “Min interval” panel setting, or an interval-type template variable — came out as 0s, which no time-series datasource will accept.

Symptoms

  • One panel errors with interval must be greater than 0 while others on the dashboard render fine.
  • The error appears only at certain zoom levels or on a very small/large time range.
  • It started after adding an interval template variable or editing the panel’s Min interval.
  • Prometheus/Loki return the step variant while the same query works in the Explore view with a manual step.
  • A $__interval/$interval token appears literally unresolved in the query inspector.

Common Root Causes

  • An interval-type template variable with an empty or malformed value, so $interval expands to nothing or 0s.
  • “Min interval” set to 0, blank, or a bad unit (0, s, 1 without a unit) in the panel/datasource query options.
  • A range vector using [$__interval] when $__interval resolves to 0s — tiny time range over huge maxDataPoints, or maxDataPoints set to 0.
  • A custom variable feeding step whose current value is empty (no default selected).
  • Hardcoded [0s] or rate(...[$interval]) where the variable never got a value.
  • Datasource timeInterval unset so Grafana can’t floor $__interval to a sane minimum.

Diagnostic Workflow

1. Read the resolved query, not the template. The query inspector shows what actually went to the datasource:

Panel → Inspect → Query → expand the request

Look for step=0, [0s], or an unexpanded $interval token — that pinpoints which interval is zero.

2. Check the interval template variable. If the panel uses $interval, confirm the variable is an Interval type with real values and a selected default:

Dashboard settings → Variables → <interval var>
Type: Interval
Values: 1m,5m,10m,30m,1h
Auto option: on (Step count e.g. 30)

An interval variable with no selected value expands to empty → 0s.

3. Set a valid “Min interval”. In the panel’s query options, set Min interval to the real scrape interval (never 0):

Query options → Min interval: 15s
Max data points: (leave default / >0)

4. Set the datasource timeInterval so $__interval/$__rate_interval always floor to a positive value. Provisioned:

apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    jsonData:
      timeInterval: 15s   # floors $__interval; prevents 0s steps

5. Prefer $__rate_interval over $__interval in rate()/irate() so the step is always at least the scrape interval:

rate(http_requests_total{job="$job"}[$__rate_interval])

6. Reproduce against the backend to confirm the fix resolves a positive step:

# A valid, positive step succeeds
curl -s -G http://prometheus:9090/api/v1/query_range \
  --data-urlencode 'query=up' --data-urlencode 'start=1720000000' \
  --data-urlencode 'end=1720003600' --data-urlencode 'step=15' | jq '.status'
# step=0 returns the "zero or negative ... step" error

Example Root Cause Analysis

A dashboard added a template variable $interval to let users pick the aggregation window, and one time-series panel then failed with interval must be greater than 0 — but only for users opening the board via a shared link.

The query inspector showed the request going out with [0s] in the range vector. The $interval variable was defined as an Interval type but had no default value selected; interactive users happened to pick one, so it worked for them, while the shared link loaded the variable empty, expanding $interval to nothing and the range to [0s].

Fix: set a default value on the interval variable (5m) and enabled the Auto option with a sensible step count, and set the datasource timeInterval: 15s as a floor. The panel rendered for everyone, including cold shared-link loads. The zero step was purely an unset variable default, not a query bug.

Prevention Best Practices

  • Give every interval template variable a default value and enable the Auto option so it never expands to empty.
  • Set a datasource timeInterval matching the scrape interval to floor $__interval above zero.
  • Set a non-zero “Min interval” on panels that aggregate, rather than leaving it blank.
  • Use $__rate_interval for rate() so the step is always at least one scrape.
  • Keep maxDataPoints at its default (or >0); a zero there can drive $__interval to 0s.
  • Test dashboards via a cold shared link, not just interactively, so unset variable defaults surface before users hit them.

Quick Command Reference

# Inspect the resolved request (UI): Panel → Inspect → Query

# Confirm a positive step works against Prometheus
curl -s -G http://prometheus:9090/api/v1/query_range \
  --data-urlencode 'query=up' --data-urlencode 'step=15' \
  --data-urlencode 'start=1720000000' --data-urlencode 'end=1720003600' | jq '.status'

# Verify the datasource timeInterval floor
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" \
  http://localhost:3000/api/datasources/name/Prometheus | jq '.jsonData.timeInterval'

Conclusion

interval must be greater than 0 means the query’s computed step resolved to 0s — almost always an interval template variable with no default, a blank “Min interval”, or a missing datasource timeInterval. Read the resolved request in the query inspector to see which interval is zero, give interval variables a default, floor $__interval with timeInterval, and prefer $__rate_interval for rates. Testing via a cold shared link catches the unset-default case before users do.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.