wppaste
WordPress

wp_send_json_error( mixed $value = null, int $status_code = null, int $flags = 0 ): never

Since
3.5.0, 4.1.0, 4.7.0, 5.6.0
Source
wp-includes/functions.php:4663

Terminates an Ajax request by echoing a JSON object with success set to false and the optional $value under a data key, then exits. Pass a WP_Error object as $value and its error codes and messages are flattened into an array of code and message pairs before encoding. Because its return type is never, any code written after the call in the same function is unreachable, so use its counterpart wp_send_json_success for the happy path.

Sends a JSON response back to an Ajax request, indicating failure.

Description

If the $value parameter is a WP_Error object, the errors within the object are processed and output as an array of error codes and corresponding messages. All other types are output without further processing.

Compatibility

WordPress
since 5.6.0
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$valuemixedoptional
Data to encode as JSON, then print and die. Default null.Default: null
$status_codeintoptional
The HTTP status code to output. Default null.Default: null
$flagsintoptional
Options to be passed to json_encode(). Default 0.Default: 0

Return value

never

Code examples

Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.

Return WP_Error validation messages from an Ajax handler

A comment-submission Ajax callback rejects an empty, too-frequent comment by collecting the problems into a WP_Error before responding.

$comment_error = new WP_Error();
$comment_error->add( 'empty_content', 'Please enter a comment before submitting.' );
$comment_error->add( 'rate_limited', 'You are commenting too quickly, please wait a moment.' );

wp_send_json_error( $comment_error, 422 );

Each error code in the WP_Error object can hold more than one message, and every message becomes its own entry in the output array.

Send a custom HTTP status code and pretty-printed JSON for a failed meta check

A quick-edit save handler for post 2 checks a 'stock' meta field that the baseline install never sets, so the numeric check always fails and the error path runs.

$post_id = 2;
$stock   = get_post_meta( $post_id, 'stock', true );

if ( ! is_numeric( $stock ) ) {
	wp_send_json_error(
		array(
			'post_id' => $post_id,
			'field'   => 'stock',
			'message' => 'Stock quantity meta is missing or not numeric.',
		),
		422,
		JSON_PRETTY_PRINT
	);
}

echo 'Stock check passed.';

The final echo never runs here because the empty 'stock' meta always fails the is_numeric() check and wp_send_json_error() ends the script.

Common problems and fixes · 4

Why does my Ajax response have success: false but no data key at all?

The function only adds 'data' to the response array when isset( $value ) is true. Calling wp_send_json_error() with no arguments leaves $value at its default of null, so the isset() check fails and 'data' is skipped entirely.

Why do I get an array of objects instead of one error message when I pass a WP_Error?

The function loops over every code in $value->errors and every message under each code, pushing a { code, message } pair for each one into $result. A WP_Error with multiple codes or multiple messages per code always produces multiple array entries.

Can I run any cleanup code right after calling wp_send_json_error()?

No. The function's own docs state $value is printed "then die", and its return type is documented as never. Once wp_send_json() runs inside it, the request ends immediately.

Why do URLs or other strings in my JSON response come back with escaped slashes?

The third parameter, $flags, defaults to 0 and is passed straight through to json_encode(), which escapes forward slashes as \/ unless told otherwise.

Alternatives and related functions

wp_send_json_success
When the Ajax request succeeded and you want the same success/data JSON envelope with success set to true instead of false.
wp_send_json
When you need full control over the shape of the response array instead of the fixed success/data wrapper this function builds for you.
WP_Error
When you need to accumulate one or more coded validation or processing errors before handing them to wp_send_json_error() for flattening.
rest_ensure_response
When the failing endpoint is a REST API route rather than an admin-ajax.php handler, since REST responses use WP_REST_Response and WP_Error differently than admin-ajax JSON.

Performance profile

How much work a call to wp_send_json_error() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Heavy

Reads stored settings via get_option(), cached per request but not free on a cold cache.

Scaling
Scales with input

The body loops, so the work grows with what you pass in.

Instructions
12–24

Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 36.

Plugin surface
None

Nothing here hands control to plugin code.

Called by
50

50 places in core call this, so the cost is paid more often than your own code shows.

What it touches

  • hookthird-party callbacksdo_action()one call below wp_send_json_error()
  • optionoption read or writeget_option()one call below wp_send_json_error()

Further down the call graph this can also reach cache, serialize, query and transient. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.

What one call costs · 2 distinct outcomes

One number would be a lie: the work depends on which branch runs. These are every distinct cost wp_send_json_error() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
!isset($value)12wp_send_json()
isset($value)18–24is_wp_error(), wp_send_json()

Across PHP versions

Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 36 instructions, 12–24 executed per call, 6 branches. The work does not change between versions.

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Uses · 2

Used by · 50

Show all 50

Source code

function wp_send_json_error( $value = null, $status_code = null, $flags = 0 ) {	$response = array( 'success' => false ); 	if ( isset( $value ) ) {		if ( is_wp_error( $value ) ) {			$result = array();			foreach ( $value->errors as $code => $messages ) {				foreach ( $messages as $message ) {					$result[] = array(						'code'    => $code,						'message' => $message,					);				}			} 			$response['data'] = $result;		} else {			$response['data'] = $value;		}	} 	wp_send_json( $response, $status_code, $flags );}

Changelog

Introduced in 3.5.0. One change between 6.7.7 and 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

7.1.0
Return type changed from none to never.verified against source
5.6.0
The $flags parameter was added.from the docblock
4.7.0
The $status_code parameter was added.from the docblock
4.1.0
The $value parameter is now processed if a WP_Error object is passed in.from the docblock
3.5.0
Introduced.from the docblock

About this page

Parsed data
Generated from the wordpress-develop 7.1.0 tag, from src/wp-includes/functions.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.