Grafana Error Guide: '413 Request Entity Too Large' — Fix Large Dashboard Saves
Fix Grafana 413 Request Entity Too Large when saving big dashboards or uploading images: raise reverse-proxy body limits, tune Grafana's own limits, and shrink the dashboard JSON.
- #grafana
- #observability
- #troubleshooting
- #errors
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 serves and saves dashboards as JSON over HTTP. When a dashboard grows large — dozens of panels, big inline SVGs on a canvas panel, long variable lists, or a snapshot upload — the save request body can exceed a size limit set by a reverse proxy in front of Grafana (Nginx, a Kubernetes Ingress, a cloud load balancer) or by Grafana itself. The proxy rejects the request before Grafana ever processes it and returns a 413.
The literal errors you will see in the browser, the toast, or the network response:
413 Request Entity Too Large
{"message":"error reading the request body","traceID":""}
# Nginx-fronted Grafana returns an HTML body:
<html><head><title>413 Request Entity Too Large</title></head>
<body><center><h1>413 Request Entity Too Large</h1></center>
<hr><center>nginx</center></body></html>
The tell: the response Server header is usually nginx or the load balancer, not Grafana — the request died at the proxy, so nothing appears in Grafana’s own logs.
Symptoms
- “Save dashboard” fails with a red toast, but small dashboards save fine.
- Importing a large dashboard JSON or uploading a snapshot/image fails.
- The failing request is a
POST/PUTto/api/dashboards/dbor/api/snapshots. - Grafana’s server log shows nothing for the failed save (the proxy blocked it).
- The response body is an Nginx/HAProxy/Ingress error page, not Grafana JSON.
Common Root Causes
1. Reverse-proxy body-size limit (most common)
Nginx defaults client_max_body_size to 1 MB. A dashboard with many panels or an inline image easily exceeds that, and Nginx returns 413 before proxying to Grafana.
2. Kubernetes Ingress (nginx) proxy-body-size
The ingress-nginx controller applies its own proxy-body-size (default 1m) via annotation/ConfigMap, independent of any Grafana setting.
3. Cloud load balancer / API gateway limit
An ALB, GCP LB, or API gateway in front of the Ingress can impose its own request-size cap.
4. Genuinely bloated dashboard JSON
Base64 images embedded in canvas/text panels, thousands of static variable values, or accumulated __inputs/panel duplication inflate the payload to megabytes.
5. Snapshot / rendered-image uploads
Publishing a snapshot or an image-renderer payload sends a much larger body than a normal save.
Diagnostic Workflow
Step 1: Confirm the 413 comes from the proxy, not Grafana
Reproduce the save with devtools open and inspect the failing request, or replay it:
# Save a dashboard via the API and watch the status + Server header
curl -s -o /dev/null -w "%{http_code} %{size_upload} bytes\n" \
-X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data @big-dashboard.json \
https://grafana.example.com/api/dashboards/db
# Read the response headers to see who answered
curl -sI -X POST -H "Authorization: Bearer $TOKEN" \
--data @big-dashboard.json \
https://grafana.example.com/api/dashboards/db | grep -iE "server|http/"
If Server: nginx and Grafana’s log is silent, the proxy rejected it.
Step 2: Measure the payload
# How big is the dashboard body actually?
du -h big-dashboard.json
jq '[.dashboard.panels[]] | length' big-dashboard.json # panel count
# Find base64-embedded images bloating the JSON
grep -oE 'data:image/[a-z]+;base64,' big-dashboard.json | wc -l
Step 3: Raise the Nginx body limit
# nginx.conf (self-managed) — server or location block
location /api/ {
client_max_body_size 25m;
proxy_pass http://grafana_upstream;
}
Step 4: Raise the Kubernetes Ingress limit
# Ingress annotations for ingress-nginx
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "25m"
Or globally in the controller ConfigMap:
# ingress-nginx controller ConfigMap
data:
proxy-body-size: "25m"
Step 5: Check Grafana’s own limits
Grafana can also cap request bodies. Confirm these are not the bottleneck once the proxy is fixed:
# grafana.ini
[dataproxy]
# streaming/proxy body handling
[snapshots]
# snapshot uploads
[security]
# nothing here caps size directly, but keep an eye on reverse-proxy TLS buffers
Grafana behind its own subpath still needs root_url set correctly so the corrected request routes properly:
[server]
root_url = https://grafana.example.com/
Step 6: Shrink the dashboard if it is genuinely bloated
- Move base64-embedded images out of panels; reference a URL instead.
- Replace huge static
customvariable lists with aqueryvariable. - Split a mega-dashboard into linked dashboards.
Example Root Cause Analysis
A team’s platform dashboard grew to 60 panels including two canvas panels with embedded PNG logos. Saving it from the UI failed with a red “Request Entity Too Large” toast; small dashboards saved fine. Grafana’s server log showed nothing for the failed POST /api/dashboards/db.
Replaying the save with curl -sI returned Server: nginx and 413, proving the ingress-nginx controller blocked it. du -h showed the exported JSON at 3.1 MB, well over the ingress default proxy-body-size: 1m, driven mostly by two base64 PNGs (grep found the data:image/png;base64, markers).
Fix: set nginx.ingress.kubernetes.io/proxy-body-size: "25m" on the Grafana Ingress and move the logos to a hosted URL, which dropped the JSON to ~180 KB. The save succeeded immediately. The root cause was a proxy body limit, not Grafana — but the embedded images were the reason the payload was large enough to hit it.
Prevention Best Practices
- Set
proxy-body-size/client_max_body_sizeon every proxy in front of Grafana to a sane value (e.g. 25 MB) so normal large dashboards save; see more Grafana guides. - Keep the limit consistent across all layers (LB → Ingress → Nginx) so the smallest one doesn’t silently win.
- Never embed base64 images in dashboard JSON; reference hosted assets.
- Prefer
queryvariables over huge static lists to keep JSON small. - Split very large dashboards into linked focused dashboards.
- Provision dashboards from files so payload size is caught in review, not at save time.
Quick Command Reference
# Who returned the 413?
curl -sI -X POST -H "Authorization: Bearer $TOKEN" \
--data @big-dashboard.json \
https://grafana.example.com/api/dashboards/db | grep -iE "server|http/"
# Measure the payload
du -h big-dashboard.json
grep -oE 'data:image/[a-z]+;base64,' big-dashboard.json | wc -l
# Raise limits
# nginx: client_max_body_size 25m;
# ingress: nginx.ingress.kubernetes.io/proxy-body-size: "25m"
Conclusion
A Grafana 413 almost always comes from a proxy, not Grafana. Fix it in order:
- Confirm the
Serverheader and Grafana’s silent log to prove the proxy rejected it. - Measure the dashboard body and find what’s bloating it.
- Raise
client_max_body_size/proxy-body-sizeconsistently across every proxy layer. - Shrink the JSON by removing embedded images and static lists so you’re not just papering over bloat.
Raising the limit unblocks the save; trimming the JSON keeps it from creeping back.
More Grafana prompts & error guides
Every Grafana AI prompt and troubleshooting guide, in one place.
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.