Opened 5 months ago
Last modified 8 weeks ago
#64256 new enhancement
Add HTTP 500 status code for WordPress critical error messages
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Milestone: | 7.1 | Priority: | normal |
| Severity: | normal | Version: | |
| Component: | Bootstrap/Load | Keywords: | has-patch changes-requested has-test-info has-screenshots |
| Focuses: | Cc: |
Description
Summary
Ensure HTTP 500 status code is always returned for WordPress critical error messages
Component
Bootstrap/Load (or Site Health)
Description
Currently, when WordPress displays the critical error message "There has been a critical error on this website.", it does not consistently return an HTTP status code. While the documentation mentions that fatal errors "typically" return HTTP 500, there is no guarantee that monitoring systems can reliably detect these errors.
Problem
Monitoring tools cannot reliably detect WordPress critical errors because:
- No HTTP status code is guaranteed to be returned
- The response may appear as HTTP 200 (success) to monitoring systems
- Critical errors go undetected until manual inspection
- Existing documentation mentions "typically 500" but doesn't guarantee monitoring-friendly behavior
Related Tickets
Related to ticket #44458 (WSOD - White Screen of Death) which addresses error handling improvements.
Proposed Solution
Ensure that WordPress always sets HTTP status code 500 when displaying critical error messages, regardless of whether a custom php-error.php template exists or not. This ensures:
- Monitoring systems can automatically detect critical errors
- HTTP status codes correctly reflect the error state
- Standard HTTP error handling works as expected
- Consistent behavior across all WordPress installations
Implementation Options
Option 1: Always set HTTP 500
Modify _default_wp_die_handler() in wp-includes/functions.php to always set HTTP status code 500 when displaying critical error messages, even if headers were already sent.
Option 2: Filter/Feature Flag
Add an optional filter force_500_on_fatal_error that allows forcing HTTP status code 500 for fatal errors, ensuring backward compatibility while enabling monitoring-friendly behavior.
Option 3: Ensure php-error.php sets status code
Document and ensure that custom php-error.php templates should set HTTP status codes, and provide a default implementation that always sets 500.
Current Behavior
class-wp-fatal-error-handler.phpsets'response' => 500in args (line 212)_default_wp_die_handler()callsstatus_header($parsed_args['response'])(line 3884)- However, this only works if
!did_action('admin_head')and headers haven't been sent - Custom
php-error.phptemplates may not set status codes
Testing
Tested scenarios:
- cURL to verify HTTP status code:
curl -I https://example.com/test-fatal-error.php - Browser developer tools to check response headers
- Monitoring systems to verify error detection
- Cases where headers were already sent
Backward Compatibility
This change should be backward compatible:
- Only affects HTTP status codes, not error messages
- Doesn't change existing error handling logic
- Can be implemented as opt-in via filter if needed
Use Case
Monitoring systems rely on HTTP status codes to detect server errors. Currently, WordPress critical errors may not return HTTP 500, causing:
- False negatives in monitoring alerts
- Delayed detection of critical issues
- Inconsistent error reporting
References
- WordPress documentation mentions fatal errors "typically" return HTTP 500
- Related to ticket #44458 (WSOD improvements)
- Monitoring systems require reliable HTTP status codes for error detection
Attachments (3)
Change History (15)
#2
@
5 months ago
Thank you for the feedback! You're absolutely right on both points. I've updated the patch to address these issues.
Changes Made
- Removed Redundant String Checks: The patch now uses a single, language-independent method instead of checking multiple strings.
- Language-Independent Solution: Instead of string matching (which fails with translations), the patch now:
- Checks for error code
'internal_server_error'- This is the code used by WordPress fatal error handler (seeclass-wp-fatal-error-handler.phpline 238) - Also checks
$parsed_args['code']- In case the code is set there instead - Ensures HTTP 500 if response is already 500 - Covers cases where the fatal error handler already set it
Why This Works
- Language-independent: Error code
'internal_server_error'is always the same, regardless of language - Uses WordPress internals: The fatal error handler creates WP_Error with this exact code
- Covers all cases: Checks both WP_Error code and parsed_args code
- No redundancy: Single, clear check
The updated patch is attached.
#4
@
5 months ago
- Keywords has-patch changes-requested added
- Milestone changed from Awaiting Review to 7.0
This makes sense to me.
Using this sample plugin code, for example:
<?php add_action( 'init', function () { non_existing_function(); } );
I get a 200 OK response, unexpectedly, even though PHP is dumping out:
Fatal error: Uncaught Error: Call to undefined function non_existing_function()
@swissky Can you open a pull request to facilitate collaboration and automated checks?
This ticket was mentioned in PR #10579 on WordPress/wordpress-develop by @whiteshadow01.
5 months ago
#5
#6
@
5 months ago
Since the author hasn't replied in 2 weeks, I have opened a PR on github as requested by @westonruter
#7
@
3 months ago
- Keywords has-test-info has-screenshots added
Patch Testing Report
Patch Tested: https://github.com/WordPress/wordpress-develop/pull/10579/
Environment
- WordPress: 7.0-alpha-61215-src
- PHP: 8.2.29
- Server: nginx/1.29.4
- Database: mysqli (Server: 8.4.7 / Client: mysqlnd 8.2.29)
- Browser: Opera
- OS: macOS
- Theme: Twenty Twenty-One 2.7
- MU Plugins: None activated
- Plugins:
- Code Snippets 3.9.4
- Test Reports 1.2.1
Steps taken
- Add the following code via Code Snippets or functions.php to "trigger" a fatal error
add_action( 'init', function () {
non_existing_function();
} );
- View frontend and check document headers using Chrome Dev Tools
- Confirm 200 OK Status code
- Apply patch
- Refresh the homepage and check document headers again
- ❌ Patch is failing. It's still displaying the 200 OK status code.
Expected result
- We are expecting to see HTTP 500 status code when an internal server error occurs
Screenshots/Screencast with results
#8
@
2 months ago
Reproduction Report
Description
This report does not validates whether the issue can be reproduced.
Environment
- WordPress: 7.0-alpha-20260203.151637
- PHP: 8.2.30
- Server: Apache/2.4.66 (Unix) PHP/8.2.30
- Database: mysqli (Server: 10.6.24-MariaDB / Client: mysqlnd 8.2.30)
- Browser: Firefox 148.0
- OS: macOS
- Theme: Twenty Twenty-Five 1.4
- MU Plugins: None activated
- Plugins:
- Test Reports 1.2.1
Actual Results
- ❌ Error condition doesn't occurs (not reproduced).
Setps taken
- Add the following code via Code Snippets or functions.php to "trigger" a fatal error
add_action( 'init', function () {
non_existing_function();
} );
- View frontend and check document headers with inspector
- ❌ Status code is already 500
Expected Results
- ✅ We should get a status code 200.
Actual Results
- ❌ We get a status code 500.
Screeshots
@mindctrl commented on PR #10579:
2 months ago
#9
@shivamdev-lgtm are you able to address the remaining review comments?
@whiteshadow01 commented on PR #10579:
2 months ago
#10
Yes I'll take it up tomorrow @mindctrl
@whiteshadow01 commented on PR #10579:
2 months ago
#11
@mindctrl I have fixed the rest of the comments. Please take a look



Hi there, welcome back to WordPress Trac! Thanks for the ticket.
Looking at the patch, checking if the message contains either
critical errororThere has been a critical errorseems redundant, as the first one should suffice. But more importantly, how would this work for messages translated into other languages?