json_encode() returns false on invalid UTF-8 and gives no indication why, which on a site with content pasted from Word is a JSON response that is silently empty.
$json = wp_json_encode( $data );
if ( false === $json ) {
return new WP_Error( 'encode_failed', 'Response could not be encoded.' );
}
wp_json_encode() attempts to fix the encoding before giving up, using the site charset, and it degrades depth rather than failing outright on deeply nested data. It is not a substitute for storing valid UTF-8 — it is the difference between a broken response and a broken response you can see. Checking the return value at all is the part most code omits.