Add a setting to enforce HTML debug responses (Fixing debugging workflow after #36456)

I’d like to propose a new feature/setting to address a developer experience regression introduced by the recent changes in Ticket #36456 (Improved content type negotiation for 500 response).

The Problem: Ticket #36456 modified django.views.debug.technical_500_response to strictly respect the client’s Accept header. While this is technically correct, it heavily impacts a common debugging workflow.

Many developers rely on the HTML response in Chrome DevTools’ (or other browsers’) Network Preview tab to read Django’s rich 500 error page when debugging API calls (fetch/XHR). Because these JavaScript requests often don’t explicitly prefer text/html, Django now returns the plain text traceback. The plain text version is much harder to read and navigate in the browser console or network tab compared to the interactive HTML debug page.

Why not just fix the frontend? Updating the Accept header across different frontend systems just to accommodate local debugging is time-consuming. Furthermore, it risks breaking existing production logic, as many frontend conditions depend on the request’s content type behaving normally.

Proposed Solution: Introduce a new setting (for example, DEBUG_TECHNICAL_ERROR_FORMAT = "text/html" or similar) that allows developers to opt-in to the legacy behavior when DEBUG = True. If this setting is enabled, Django would always return the rich HTML debug page upon a crash, bypassing the strict content-type negotiation.

I believe this would restore a beloved part of Django’s developer experience for SPAs and API-heavy projects without rolling back the correctness achieved in #36456.

I would love to hear your thoughts on this!

This request was also sent via a new ticket in #37207 (Add a backend setting to enforce HTML response for technical 500 errors) – Django. I closed as wontfix with this rationale:

The behavior introduced in #36456 is intentional: technical_500_response now respects the Accept header sent by the client. If your frontend sends requests without text/html in Accept, that is a client-side problem, not a server-side configuration problem.

A Django setting does nothing for the actual negotiation contract and just punches a hole in behavior that was deliberately designed and released. It is also not scoped to DEBUG mode, which means it could accidentally affect production if someone leaves it set.

For cases where you need unconditional HTML output, technical_500_response is a public API you can override in your project with a few lines. That is the right scope for this kind of customization.

More broadly, Django is actively avoiding adding new top-level settings unless truly necessary, and when it does add configuration, the direction is toward grouped dict-based settings (like DATABASES, STORAGES, CACHES, MAILERS). A one-off boolean to override content negotiation does not meet that bar.