WordPress REST API returns 500 error when updating serialized meta with an unchanged value

Take care when updating posts via the WordPress REST API to not send unchanged serialized meta values. The entire update will fail and return a 500 error. The JSON response looks like this:

{
	"code": "rest_meta_database_error",
	"message": "Could not update meta value in database.",
	"data": {
		"key": "meta_key_name",
		"status": 500
	}
}

This error comes from line 300 of wp-includes/rest-api/fields/class-wp-rest-meta-fields.php, and to understand why calls to update_metadata() return false for unchanged and serialized meta values, read on.

Let us look at like 196 of wp-includes/meta.php. We learn that if a previous value is not passed to update_metadata(), that function looks it up for a comparison and returns false if they match. During REST API calls, the previous value is not provided.

So why doesn’t the REST API return an error for updates to any post meta values?

The REST API tries to short-circuit and avoid calling update_metadata() on line 293 of class-wp-rest-meta-fields.php when the incoming value has not changed, but the conditions were not designed for serialized data:

		if ( 1 === count( $old_value ) ) {
			if ( $old_value[0] === $meta_value ) {
				return true;
			}
		}

By this time, the meta value in $old_value has been run through maybe_unserialize(), but the new value in $meta_value has not. This short circuit fails, update_metadata() is called & returns false instead of true, and the API responds with a 500 error as a result.