Grafana Error Guide: 'Dashboard import failed / invalid JSON model' — Fix a Bad Dashboard Model
Fix Grafana 'failed to load dashboard' and invalid JSON model errors: diagnose malformed JSON, schema version mismatch, unmapped inputs, and provisioning load failures.
- #grafana
- #troubleshooting
- #errors
- #provisioning
Overview
Grafana stores every dashboard as a JSON model. When you import that model — through the UI, the HTTP API, or file provisioning — Grafana parses and validates it before saving. A malformed model, an unmapped input, or a newer schema than the running Grafana understands makes the import fail outright.
The literal errors you will see:
Dashboard import failed: invalid character '}' looking for beginning of object key string
The dashboard has been changed by someone else / invalid dashboard model
level=error logger=provisioning.dashboard msg="failed to load dashboard from" file=/var/lib/grafana/dashboards/app.json error="invalid character 'x' after top-level value"
Unlike a “Data source not found” (which loads but has no data), a JSON model failure means the dashboard never loads at all — the file is rejected during parsing.
Symptoms
- UI import shows “Dashboard import failed” with a JSON parse position.
- Provisioned dashboards never appear and the log shows
failed to load dashboard from. - The API returns HTTP 400 with
invalid characterorunexpected end of JSON input. - After editing a dashboard file by hand, Grafana ignores it.
Common Root Causes
1. Malformed JSON
A trailing comma, unbalanced brace, or a template that left ${VAR} where JSON expected a value makes the parser fail immediately.
2. Wrong provisioning file wrapper
Provisioning expects the raw dashboard JSON, but the file contains an API-style {"dashboard": {...}, "overwrite": true} wrapper (or vice versa for the API).
3. Unresolved __inputs placeholders
A “share externally” export leaves ${DS_PROMETHEUS} inputs that are valid JSON strings but invalid as a runnable model on import.
4. Schema version too new
A dashboard exported from a newer Grafana carries a schemaVersion the older running instance cannot migrate.
5. Encoding / BOM issues
A UTF-8 BOM or CRLF artifacts prepended to the file break the JSON parser on the first byte.
Diagnostic Workflow
Step 1: Validate the JSON is well-formed
jq empty /var/lib/grafana/dashboards/app.json && echo "valid JSON" || echo "INVALID JSON"
python3 -m json.tool /var/lib/grafana/dashboards/app.json > /dev/null
jq prints the exact line/column of the first syntax error.
Step 2: Read the provisioning log for the reason
sudo journalctl -u grafana-server --no-pager | grep -iE "provisioning.dashboard|failed to load dashboard" | tail -20
kubectl logs deploy/grafana -n monitoring | grep -i "failed to load dashboard" | tail -20
grep -i "failed to load dashboard" /var/log/grafana/grafana.log | tail -20
Step 3: Confirm the correct file shape
For file provisioning the file must be the bare dashboard object. For the API it must be wrapped:
# API import expects a wrapper
curl -s -X POST -H "Authorization: Bearer $GRAFANA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"dashboard": '"$(cat app.json)"', "overwrite": true}' \
http://localhost:3000/api/dashboards/db | jq
A 400 with invalid character here points back at the JSON itself.
Step 4: Check for BOM/CRLF and schema version
head -c 3 app.json | xxd # ef bb bf == UTF-8 BOM to strip
grep -o '"schemaVersion": *[0-9]*' app.json
If schemaVersion exceeds what your Grafana version supports, re-export from a matching version or import through the UI, which migrates older models forward.
Step 5: Point provisioning at the right folder
# /etc/grafana/provisioning/dashboards/default.yaml
apiVersion: 1
providers:
- name: 'default'
orgId: 1
folder: 'Services'
type: file
disableDeletion: false
options:
path: /var/lib/grafana/dashboards
Example Root Cause Analysis
A CI job writes dashboards into /var/lib/grafana/dashboards, but one never shows up. The log:
logger=provisioning.dashboard msg="failed to load dashboard from" file=/var/lib/grafana/dashboards/app.json error="invalid character ',' looking for beginning of object key string"
Running jq empty app.json points at a trailing comma after the last panel object — valid to a templating tool, invalid JSON. The dashboard was rendered from a Jinja template that left a comma before the closing ].
Fix: remove the trailing comma (or pipe the template output through jq . in CI to normalize it before writing). Grafana’s provisioner rescans on its interval and the dashboard appears. The root cause was a template producing technically-invalid JSON, caught immediately by jq.
Prevention Best Practices
- Run
jq empty(orpython3 -m json.tool) on every dashboard file in CI before it ships; see more Grafana guides. - Keep provisioning files as bare dashboard objects and API payloads wrapped — never mix the two shapes.
- Strip UTF-8 BOMs and normalize line endings when generating JSON from templates.
- Export dashboards from a Grafana version that matches production so
schemaVersionmigrates cleanly. - Resolve
${DS_*}inputs to real UIDs before provisioning instead of shipping raw share-externally exports. - Version dashboards in git and review diffs so a stray edit cannot silently break the model.
Quick Command Reference
# Validate JSON and pinpoint the syntax error
jq empty /var/lib/grafana/dashboards/app.json
python3 -m json.tool /var/lib/grafana/dashboards/app.json > /dev/null
# Why did provisioning reject it?
sudo journalctl -u grafana-server | grep -i "failed to load dashboard" | tail -20
kubectl logs deploy/grafana -n monitoring | grep -i "failed to load dashboard" | tail -20
# BOM / schema checks
head -c 3 app.json | xxd
grep -o '"schemaVersion": *[0-9]*' app.json
# API import (expects wrapper)
curl -s -X POST -H "Authorization: Bearer $GRAFANA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"dashboard": '"$(cat app.json)"', "overwrite": true}' \
http://localhost:3000/api/dashboards/db | jq
Conclusion
A “failed to load dashboard” / invalid JSON model error is a parse-time rejection — Grafana never gets far enough to render anything. Diagnose in order:
- Prove the file is valid JSON with
jq empty; it names the exact bad character. - Read the provisioning log for the precise reason (syntax vs. wrapper vs. schema).
- Match the file shape to the load path — bare object for provisioning, wrapped for the API.
- Strip BOM/CRLF and reconcile
schemaVersionwith your Grafana version.
Validate JSON in CI once and malformed models stop reaching Grafana at all.
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.