Consistent PHP Error

Hi Team

We’re seeing this error on only one of our sites but it is cropping up regularly. Thinking it might be a heartbeat issue with reloading the dashboard widget, I did remove the dashboard widget with PHP but it didn’t fix the issue. it’s not effecting the front end of the site but I’d be keen to resolve it as the client is getting these emails multiple times a day :slight_smile:

Here’s the error details:

When seeking help with this issue, you may be asked for some of the
following information:
WordPress version 6.1.1
Active theme: Divi (version 4.19.3)
Current plugin: WP fail2ban (version 4.4.0.9)
PHP version 7.4.33

Error Details

An error of type E_ERROR was caused in line 114 of the file
/var/www/katiesuzukimusic.com/htdocs/wp-content/plugins/wp-fail2ban/admin/widgets.php.
Error message: Uncaught TypeError: Argument 1 passed to
org\lecklider\charles\wordpress\wp_fail2ban\heartbeat_received() must
be of the type array, null given, called in
/var/www/katiesuzukimusic.com/htdocs/wp-includes/class-wp-hook.php on
line 308 and defined in
/var/www/katiesuzukimusic.com/htdocs/wp-content/plugins/wp-fail2ban/admin/widgets.php:114
Stack trace:
#0 /var/www/katiesuzukimusic.com/htdocs/wp-includes/class-wp-hook.php(308):
org\lecklider\charles\wordpress\wp_fail2ban\heartbeat_received()
#1 /var/www/katiesuzukimusic.com/htdocs/wp-includes/plugin.php(205):
WP_Hook->apply_filters()
#2 /var/www/katiesuzukimusic.com/htdocs/wp-admin/includes/ajax-actions.php(3465):
apply_filters()
#3 /var/www/katiesuzukimusic.com/htdocs/wp-includes/class-wp-hook.php(308):
wp_ajax_heartbeat()
#4 /var/www/katiesuzukimusic.com/htdocs/wp-includes/class-wp-hook.php(332):
WP_Hook->apply_filters()
#5 /var/www/katiesuzukimusic.com/htdocs/wp-includes/plugin.php(517):
WP_Hook->do_action()
#6 /var/www/katiesuzukimusic.com/htdocs/wp-admin/adm

Thanks for the report!

TL;DR: Another plugin is processing the heartbeat before WPf2b and returning null instead of an array; add a workaround.

If you look at wp_ajax_heartbeat() (about line 3416 in /wp-admin/includes/ajax-actions.php), the heartbeat filter is called (about line 3455):

	if ( ! empty( $data ) ) {
		/**
		 * Filters the Heartbeat response received.
		 *
		 * @since 3.6.0
		 *
		 * @param array  $response  The Heartbeat response.
		 * @param array  $data      The $_POST data sent.
		 * @param string $screen_id The screen ID.
		 */
		$response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
	}

And near the start of the function (about line 3421):

	$response    = array();

As you can see, WordPress always passes an array, so for it to be null the only possible explanation is that something else processed the filter first and returned null.

Obviously the “correct” solution is to track down which plugin is misbehaving and get the author to fix it, but that’s likely to be quite a lot of work and take quite some time.

However, in this case I think the workaround is simple and harmless enough to go with that instead. Basically, just change line 114 in wp-fail2ban/admin/widgets.php to:

function heartbeat_received($response, array $data, string $screen_id)

and that should solve the problem.

I’ll add it to the next release.

(Edited to correct the code; now included in v5.0.0 with tests).