1.15.5 — Error pages that look like your product
Editorial identity incomplete
2026-08-20
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.