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

Grafana Error Guide: 'Dashboard cannot be deleted because it was provisioned'

Fix 'Dashboard cannot be deleted because it was provisioned' in Grafana — remove the source JSON, set disableDeletion, or unprovision the provider, then reload provisioning to delete it cleanly.

  • #grafana
  • #troubleshooting
  • #errors
  • #provisioning

Overview

When a dashboard is loaded by a file provider, Grafana marks it as provisioned and protects it from UI deletion and (depending on config) UI edits. The source of truth is the JSON file on disk, so deleting it in the UI would just be undone on the next provisioning reload. Grafana blocks the delete outright with a clear message.

The literal errors you will see:

Dashboard cannot be deleted because it was provisioned
{"message":"Dashboard cannot be deleted because it was provisioned","status":"error"}
status=400 msg="Failed to delete dashboard" error="dashboard cannot be deleted because it was provisioned"

It occurs when you try to delete a dashboard (UI trash icon or DELETE /api/dashboards/uid/<uid>) that Grafana knows came from a provisioning provider.

Symptoms

  • The UI delete button is greyed out or returns the “provisioned” error.
  • DELETE /api/dashboards/uid/<uid> returns 400 with the provisioned message.
  • A “removed” dashboard reappears after the provisioning interval.
  • The dashboard shows a provisioned banner/lock in the UI.
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \
  http://localhost:3000/api/dashboards/uid/<uid>
{"message":"Dashboard cannot be deleted because it was provisioned","status":"error"}

Common Root Causes

1. The dashboard is still provisioned from a file

The JSON still exists in a provider’s options.path, so Grafana keeps re-applying it. Deleting in the UI is intentionally blocked.

curl -s -H "Authorization: Bearer $TOKEN" \
  http://localhost:3000/api/dashboards/uid/<uid> | jq '.meta.provisioned, .meta.provisionedExternalId'
true
"prod-overview.json"

meta.provisionedExternalId names the source file.

2. disableDeletion: true on the provider

Even removing the file won’t delete the dashboard if the provider sets disableDeletion: true, which keeps provisioned dashboards after their files disappear.

providers:
  - name: 'default'
    type: file
    disableDeletion: true          # deletions from disk are NOT propagated
    options:
      path: /var/lib/grafana/dashboards

3. Trying to delete via the wrong layer

Attempting the delete in the UI/API instead of removing the source JSON — the file is the real controller of the dashboard’s existence.

4. Multiple providers or a stale mount

Two providers reference overlapping paths, or an old ConfigMap/volume still carries the JSON, so removing one copy leaves another.

Diagnostic Workflow

Step 1: Confirm it’s provisioned and find the source file

curl -s -H "Authorization: Bearer $TOKEN" \
  http://localhost:3000/api/dashboards/uid/<uid> \
  | jq '{provisioned: .meta.provisioned, sourceFile: .meta.provisionedExternalId}'

Step 2: Locate the file on disk

grep -Rl "\"uid\": *\"<uid>\"" /var/lib/grafana/dashboards/ /etc/grafana/dashboards/ 2>/dev/null
find /var/lib/grafana/dashboards -name '*.json'

Step 3: Check the provider’s deletion policy

grep -RiE "disableDeletion|path:" /etc/grafana/provisioning/dashboards/*.yaml

Step 4: Remove the source, then reload provisioning

# Delete (or stop shipping) the JSON — for K8s, remove it from the ConfigMap
rm /var/lib/grafana/dashboards/prod-overview.json

# With disableDeletion:false, reload propagates the removal
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
  http://localhost:3000/api/admin/provisioning/dashboards/reload

Step 5: If deletion is disabled, flip the policy or unprovision

providers:
  - name: 'default'
    disableDeletion: false   # allow disk removals to delete dashboards

Then restart/reload and the dashboard can be removed.

Example Root Cause Analysis

A team retires an old “Legacy Nodes” dashboard. The UI trash icon shows:

Dashboard cannot be deleted because it was provisioned

The API confirms the source:

curl -s -H "Authorization: Bearer $TOKEN" \
  http://localhost:3000/api/dashboards/uid/legacy01 | jq '.meta.provisionedExternalId'
"legacy-nodes.json"

They remove the file from the Git repo that renders the ConfigMap and redeploy — but the dashboard survives. The provider has disableDeletion: true, so removing the file is not propagated as a delete.

Fix: set disableDeletion: false on the provider, redeploy, and reload provisioning. With the file already gone and deletions now propagated, the dashboard disappears:

curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
  http://localhost:3000/api/admin/provisioning/dashboards/reload

Root cause: a provisioned dashboard can only be deleted by removing its source file and allowing the provider to propagate deletions — the UI was never the right lever.

Prevention Best Practices

  • Treat provisioned dashboards as code: delete the JSON in Git, not in the UI.
  • Set disableDeletion deliberately — true protects against accidental disk loss but means stale dashboards linger; false keeps disk and Grafana in sync.
  • Keep one provider per path to avoid duplicate/overlapping sources that survive a single removal.
  • After removing files, always reload provisioning (/api/admin/provisioning/dashboards/reload) rather than waiting/guessing.
  • Document which folders are provisioned so operators don’t attempt UI deletes.
  • See more Grafana guides and the sibling provisioning not-found guide.

Quick Command Reference

# Confirm provisioned + source file
curl -s -H "Authorization: Bearer $TOKEN" \
  http://localhost:3000/api/dashboards/uid/<uid> \
  | jq '{provisioned:.meta.provisioned, sourceFile:.meta.provisionedExternalId}'

# Find the JSON on disk
grep -Rl "\"uid\": *\"<uid>\"" /var/lib/grafana/dashboards/ 2>/dev/null

# Deletion policy
grep -RiE "disableDeletion|path:" /etc/grafana/provisioning/dashboards/*.yaml

# Remove source + reload
rm /var/lib/grafana/dashboards/<file>.json
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
  http://localhost:3000/api/admin/provisioning/dashboards/reload

Conclusion

“Dashboard cannot be deleted because it was provisioned” is Grafana protecting a file-managed dashboard from a UI delete that disk would just undo. Typical root causes:

  1. The source JSON still exists in a provider path.
  2. The provider sets disableDeletion: true, so removing the file isn’t propagated.
  3. You’re deleting at the wrong layer (UI/API instead of the file).
  4. A duplicate provider or stale mount leaves another copy.

Find meta.provisionedExternalId to name the source file, remove it (in Git/ConfigMap), ensure disableDeletion: false, then reload provisioning — that, not the UI trash icon, is the real delete path.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

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.