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

Grafana Error Guide: 'Circular dependency' in Template Variables — Break the Loop

Quick answer

Fix Grafana 'Circular dependency in dashboard variables' errors: find the self-referencing chained query variable, order dependencies correctly, and reprovision the dashboard JSON.

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

Stuck on this Grafana error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Overview

Chained (dependent) template variables let one variable’s query reference another — instance filtered by $job, pod filtered by $namespace. When those references form a loop, Grafana refuses to resolve the variable set and the dashboard fails to render, showing an error like:

Failed to upgrade legacy queries Circular dependency in dashboard variables detected. Variables: instance, job

In newer builds the templating layer reports the same condition more directly while editing a variable:

Templating [instance]: Circular dependency detected in the variable "instance"

The defining symptom: panels show no data or a red “template variable” error, the variable dropdowns are empty or stuck, and the message names two or more variables that depend on each other.

Symptoms

  • Dashboard load throws Circular dependency in dashboard variables detected naming two or more variables.
  • Variable dropdowns are empty, show a spinner forever, or never populate options.
  • Every panel using the affected variables renders “No data” or a templating error.
  • Saving a variable in the editor immediately re-throws the circular-dependency message.
  • It appeared after editing a variable query to reference another variable, or after importing a dashboard whose variable order was rearranged.

Common Root Causes

  • A variable references itself — a query variable whose expression interpolates its own name (directly, or via a regex/Filters that reuses it).
  • Two variables reference each otherA filters by $B and B filters by $A, so neither can resolve first.
  • A longer cycle through a chainA → B → C → A across three or more chained variables.
  • Copy-paste drift — a duplicated variable kept the original’s name in its query, pointing back at the wrong variable.
  • Reordered variables on import — templating resolves top-to-bottom; a dependency listed after its consumer can create an unresolvable order that surfaces as a cycle.
  • Ad-hoc / custom “all” interplay — an ad-hoc filters variable and a query variable referencing each other’s label set.

Diagnostic Workflow

Pull the dashboard JSON and inspect every variable definition and what it references — the cycle is always visible in the templating.list:

# Export the dashboard by UID and list each variable name + its query
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" \
  http://localhost:3000/api/dashboards/uid/abc123 \
  | jq -r '.dashboard.templating.list[] | "\(.name)  <=  \(.query.query // .query // .definition)"'

Example output that exposes a two-node cycle — instance depends on $job while job depends on $instance:

job       <=  label_values(up{instance="$instance"}, job)
instance  <=  label_values(up{job="$job"}, instance)

Confirm which variables interpolate which by scanning for the $name and ${name} references:

# Show every variable that references another variable
jq -r '.dashboard.templating.list[]
  | select((.query.query // .query // "" ) | test("\\$"))
  | "\(.name): \(.query.query // .query)"' dashboard.json

Break the cycle by making the dependency one-directional. Here job is the true parent, so it must NOT reference instance:

# Provisioned dashboard variables — a valid one-way chain (job -> instance)
templating:
  list:
    - name: job
      type: query
      # Parent: no reference to a child variable
      query: label_values(up, job)
      refresh: 2          # on time range change
    - name: instance
      type: query
      # Child: references the parent only
      query: label_values(up{job="$job"}, instance)
      refresh: 2

Save and reload; the dropdowns should populate job first, then instance. If the dashboard is provisioned from a file, edit the source and let the provisioning reload pick it up rather than editing in the UI (UI edits to provisioned dashboards cannot be saved).

Example Root Cause Analysis

An imported Kubernetes dashboard failed to load with Circular dependency in dashboard variables detected. Variables: namespace, pod. Every panel showed a templating error and both dropdowns were empty.

Exporting the JSON and running the jq reference scan showed the loop plainly: namespace was defined as label_values(kube_pod_info{pod="$pod"}, namespace) while pod was label_values(kube_pod_info{namespace="$namespace"}, pod). Each variable filtered by the other, so Grafana could resolve neither first. The namespace query had been copied from the pod query during editing and never had its filter removed.

The fix was to make namespace the parent with no child reference — label_values(kube_pod_info, namespace) — and keep pod filtered by $namespace. After correcting the source JSON and letting provisioning reload it, namespace populated first, pod filtered correctly, and the panels rendered. No Grafana restart was required.

Prevention Best Practices

  • Design variable chains as a strict tree: a parent never references its children, and every child references only parents defined above it.
  • When duplicating a variable, immediately rewrite its query so it does not point back at the variable it was copied from.
  • Order templating.list so each variable appears after the variables it depends on.
  • Lint dashboard JSON in CI for variables that reference each other (a simple jq check catches the common two-node cycle before merge).
  • Prefer a single ad-hoc filters variable over many mutually-referencing query variables when users just need free-form label filtering.

Quick Command Reference

# List each variable and what it references
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" \
  http://localhost:3000/api/dashboards/uid/abc123 \
  | jq -r '.dashboard.templating.list[] | "\(.name): \(.query.query // .query // .definition)"'

# Flag variables that interpolate another variable (potential cycle sources)
jq -r '.dashboard.templating.list[]
  | select((.query.query // .query // "") | test("\\$"))
  | "\(.name): \(.query.query // .query)"' dashboard.json

# Validate JSON before reprovisioning
jq empty dashboard.json && echo "valid JSON"

Conclusion

A Circular dependency in dashboard variables error is Grafana telling you your chained variables form a loop it cannot resolve — one variable references itself, or two-or-more reference each other. Export the dashboard JSON, list each variable against what it interpolates, and find the back-reference. Fix it by turning the chain into a one-way tree where parents never reference children, order the variables so dependencies come first, and reprovision from source. A tiny jq lint in CI keeps the cycle from ever reaching production again.

Free download · 368-page PDF

Fixed it? Get 500 Grafana & 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.

Did this fix your issue?

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.