Make WordPress Core

Opened 4 months ago

Closed 3 months ago

Last modified 3 months ago

#63836 closed defect (bug) (fixed)

Use more appropriate HTTP status codes for wp_die() calls in wp-admin/post.php

Reported by: kkmuffme's profile kkmuffme Owned by: callumbw95's profile callumbw95
Milestone: 6.9 Priority: normal
Severity: minor Version:
Component: General Keywords: has-patch commit
Focuses: Cc:

Description

By default wp_die uses HTTP status 500.
This is also the status PHP uses for fatal errors.
The docs state:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/500

If you're a visitor seeing 500 errors on a web page, these issues require investigation by server owners or administrators

There are many possible causes of 500 errors, including: improper server configuration, out-of-memory (OOM) issues, unhandled exceptions, improper file permissions, or other complex factors. Server administrators may proactively log occurrences of server error responses, like the 500 status code, with details about the initiating requests to improve the stability of a service in the future.

Looking at e.g.
wp_die( __( 'You attempted to edit an item that does not exist. Perhaps it was deleted?' ) );

The 500 status does not really fit the description. In fact in this 1 file, there are lots of similar cases that all should use a more appropriate HTTP status:

https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-admin/post.php#L127 => 404
https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-admin/post.php#L131 => 404 or 400
https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-admin/post.php#L135 => 403
https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-admin/post.php#L139 => 403
https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-admin/post.php#L143 => 404 or 410
and a lot more

While this seems a small, trivial issue at first the impact is quite annoying:

  • lots of NEL reports (if enabled) with status 500, making it hard to distinguish between actual, legit server issues and just WP using the wrong HTTP status
  • unnecessary extra work for server admins, since they see the 500 in their logs, but the PHP fatal is logged to another team or even if they have access, multiple teams now need to check an error that isn't an error at all - bc it's just a 404 and not a server misconfiguration
  • because 500 status usually has way more logging (and way less caching) involved, minimally more server resources are required

Attachments (3)

63836.audit.patch (4.9 KB) - added by callumbw95 4 months ago.
Add error codes to wp_die in ./src/wp-admin/post.php
63836.audit.2.patch (4.4 KB) - added by callumbw95 4 months ago.
Fix accidental removal of elseif from original patch
63836.audit.3.patch (4.4 KB) - added by callumbw95 4 months ago.
Updated patch as per @mindctrl's note around the status code 423 being changed to 400

Download all attachments as: .zip

Change History (17)

#1 @johnbillion
4 months ago

  • Keywords needs-patch added
  • Severity changed from trivial to minor

#2 @callumbw95
4 months ago

  • Keywords 2nd-opinion added

Hi @kkmuffme,

I have just taken a look into this, and it looks as though the wp_die() function is already equipped to handle an HTTP status code, either as a standalone integer or within the $args array:

  • wp_die( 'message', 'title', 404 );
  • wp_die( 'message', 'title', [ 'response' => 404 ] );

As it stands, wp_die() uses this response value to call status_header() before the die handler is ever invoked. You can see this in src/wp-includes/functions.php:line 4032. The problem isn't that wp_die() ignores the code, but rather that the vast majority of calls to this function throughout the core codebase don't provide a specific code, causing it to fall back to the default 500.

I propose the following routes to getting this issue resolved. I also think that the best solution here may be a combination of the two approaches:

  • Comprehensive Core Audit: We should systematically review the existing calls to wp_die() and update them to include the appropriate HTTP status code. As you noted, with nearly 700 instances across the codebase, this is a significant undertaking. We could prioritize the most common or critical instances first (e.g., those related to permissions, non-existent posts, or database errors).
  • Intelligent Status Code Inference: As a powerful fallback and for backward compatibility, we could enhance wp_die() with logic to infer a status code from the message string when one isn't explicitly provided. For example, checking for "not found" in the passed message and setting the status to 404. This would immediately improve responses for countless existing calls in core, themes, and plugins without requiring them all to be updated.

Combining these two strategies would give us the best of both worlds: precision from the manual audit and broad, immediate improvement from the inference logic. This would be a fantastic step toward providing more meaningful and logical response codes for developers and site administrators.

I would love to hear feedback from the community on this, and if we are happy with this plan of attack, I am happy to do an audit of wp_die() use across core. 😃

@callumbw95
4 months ago

Add error codes to wp_die in ./src/wp-admin/post.php

@callumbw95
4 months ago

Fix accidental removal of elseif from original patch

#3 @mindctrl
4 months ago

  • Keywords has-patch added; needs-patch removed

+1 for returning the most appropriate status code when possible. The patch works as expected. I like the limited scope, but curious what leads think.

TIL the 423 status code is meant for WebDAV. MDN has this note:

Note: The ability to lock a resource to prevent conflicts is specific to some WebDAV servers. Browsers accessing web pages will never encounter this status code; in the erroneous cases it happens, they will handle it as a generic 400 status code.

Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/423

Maybe those should be 400 instead.

@callumbw95
4 months ago

Updated patch as per @mindctrl's note around the status code 423 being changed to 400

#4 @westonruter
4 months ago

Related: #47393 (Comment form submission with invalid fields incorrectly returns 200 OK response)

#5 @westonruter
4 months ago

  • Milestone changed from Awaiting Review to 6.9
  • Owner set to callumbw95
  • Status changed from new to assigned

This ticket was mentioned in PR #9604 on WordPress/wordpress-develop by CallumBW95.


4 months ago
#6

Add error codes to each instance of wp_die in ./src/wp-admin/post.php

Trac ticket: [](https://core.trac.wordpress.org/ticket/63836)

This ticket was mentioned in PR #9639 on WordPress/wordpress-develop by @callumbw95.


4 months ago
#7

Add error codes to each instance of wp_die in ./src/wp-admin/post.php

Trac ticket: #63836

This ticket was mentioned in Slack in #core by callumbw95. View the logs.


4 months ago

#9 @westonruter
3 months ago

Just left a review on the PR as well. I missed the discussion above about 423 Locked. I think it is appropriate to use it, but if not, then the 409 Conflict would be more specific than 400 Bad Request.

#10 @callumbw95
3 months ago

Hey @westonruter,

Just to let you know I have seen your review on the PR now, and I have committed the requested status code changes now. Thank you for reviewing! 😃

#11 @westonruter
3 months ago

  • Keywords commit added; 2nd-opinion removed
  • Summary changed from Use more appropriate HTTP status codes for wp_die to Use more appropriate HTTP status codes for wp_die() calls in wp-admin/post.php

#12 @westonruter
3 months ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 60713:

Posts, Post Types: Use relevant HTTP status codes for wp_die() calls in wp-admin/post.php.

The status code is now explicitly set in each wp_die() call so that the default 500 status code is not sent unless it is the most appropriate.

Props callumbw95, kkmuffme, mindctrl, westonruter.
Fixes #63836.

This ticket was mentioned in Slack in #core by callumbw95. View the logs.


3 months ago

Note: See TracTickets for help on using tickets.