--- title: "1.15.5 — Error pages that look like your product" description: "Every project now ships styled error pages — 400, 403, 404, 500, 503 and an honest \"nothing published here yet\" root — in the same visual language as the hosted auth pages, light and dark. Browsers get a real page; API clients receive byte-for-byte the JSON they received before. And a fresh install…" date: "2026-08-20" tags: ["release"] canonical: "https://django-mojo.sitesmojo.com/changelog/1-15-5/" --- Every project now ships styled error pages — 400, 403, 404, 500, 503 and an honest "nothing published here yet" root — in the same visual language as the hosted auth pages, light and dark. Browsers get a real page; API clients receive byte-for-byte the JSON they received before. And a fresh install no longer greets its first operator with "Permission Denied" seconds after a successful sign-in. ### Added - **Six error states ship with the framework.** 400, 403, 404, 500, 503 and an unconfigured-root page, following the visitor's light/dark preference. Projects get them by upgrading — nothing to copy, nothing to wire up. Their CSS is self-contained, so they still render when the static pipeline is the thing that broke. - **Every page is overridable.** Drop a matching template in your own app to replace any single one. The wordmark already follows your auth theme's app title, so most projects change nothing at all. ### Changed - **A fresh install's root address now tells the truth.** It used to serve a bare "Permission Denied", which is what a brand-new deployment showed its operator immediately after a successful password reset — nothing was wrong but the page. It now says the API is running and no public site is configured there yet. - **HTML error responses always carry their true status code**, even where the status-200-on-error compatibility setting is enabled. Browsers, crawlers and uptime monitors all need the real one; the two behaviours are now independent. - **Incident reporting returns the Event it created** instead of nothing. Additive — existing callers that ignore the return value are unaffected. ### Fixed - **The 500 page carries an incident reference and nothing else.** No exception text, no stack trace, no request path. The reference is the real incident id, so "it broke" becomes a ticket you can trace, while every diagnostic detail stays in the incident record where access is controlled. Where no incident was recorded, the page renders without a reference rather than inventing one. ### Upgrade notes - **API responses are unchanged.** A caller that sends no Accept header, a wildcard, or any JSON media type gets exactly the JSON it got before — a JSON type wins even when text/html is also listed. Only a request that explicitly prefers text/html over the wildcard receives a page, so curl and typical API clients see no difference. - Only 400, 403, 404, 500 and 503 render HTML. Other statuses — including 401, 408, 429 and 440 — remain JSON for every caller. - If your project defines its own 404 or 500 handler, it keeps working untouched. The skeleton's generated URLconf now routes them through the shared renderer; adopting that is optional.