Real-time map and Live widget stop refreshing permanently after a single failed request
What happened?
Both real-time surfaces re-arm their polling timer only inside the success callback, and
neither registers an error handler on the AJAX call. As a result a single failed request, for
any reason, silently kills the refresh loop for good.
The UI stays fully responsive, only the data freezes. Nothing is logged and nothing is shown
to the user. The only way to restart it is to recreate the widget, meaning navigate away and
back, or reload the page.
Affected code, verified in 5.13.0 and still present in 6.x-dev:
plugins/UserCountryMap/javascripts/realtime-map.js, in refreshVisits():
ajax(_reportParams(firstRun)).done(gotNewReport);
The next setTimeout lives inside gotNewReport. The strings ".fail(", "error:" and "complete:"
do not appear anywhere in that file.
plugins/Live/javascripts/live.js, in _update():
ajaxRequest.setCallback(function (r) {
...
if (that.isStarted) {
window.clearTimeout(that.updateInterval);
that.updateInterval = window.setTimeout(function() { that._update(); }, that.currentInterval);
}
});
ajaxRequest.send();
ajaxHelper does expose setErrorCallback(), it is simply not used here.
Real-world trigger: any transient failure does it, a network blip, a 502 from a reverse proxy,
a response that fails to parse as JSON, a laptop waking up. The case that made this
reproducible for us is a macOS Dock web app ("Add to Dock" in Safari). The system suspends the
window as soon as it goes to the background, which aborts whatever request is in flight. With
one request every 5 seconds the race is hit within days. The same Matomo in a normal, visible
Safari tab almost never freezes, which is what made the bug look random for a long time.
What should happen?
A failed request should not end the polling loop. The timer should be re-armed on failure the
same way it is on success, so that the report resumes on its own once requests succeed again.
Today a user watching the real-time map or the Live widget can be looking at data frozen
minutes or hours earlier, with no indication that it is stale.
How can this be reproduced?
PPure client-side, no server or network manipulation needed, so it reproduces on any instance including the demo. Steps below were run on a self-hosted 5.13.0.
Open Visitors > Real-time Map (or Visitors > Real-time for the Live widget), then in the browser console.
1. Instrument, one line per poll:
jQuery(document).ajaxSend(function (e, x, o) {
console.log('REQ', new Date().toLocaleTimeString(), (o.url + '').slice(-60));
});
2. Wait for two or three REQ lines, then make the polled request fail for real, by rewriting its URL to a path that returns 403 or 404:
window.__killAjax = true;
jQuery.ajaxPrefilter(function (o) {
if (window.__killAjax && (o.url + '').indexOf('getLastVisits') > -1) {
o.url = '/plugins/__kill__' + Date.now();
}
});
3. Wait about 60 seconds, then restore:
window.__killAjax = false;
Expected: REQ lines keep appearing for the whole failure window, pointing at the bogus
URL, and go back to the normal URL once restored.
Actual: exactly one failing request, then silence. The report stays frozen indefinitely while the rest of the UI keeps responding. Navigating to another menu and back restarts it.
Two notes for whoever tries this.
Do not simulate the failure with jQuery.ajaxSetup({ beforeSend: ... }) returning
false. That path is not equivalent and it silently gives a wrong result on the live.js
half: jQuery evaluates beforeSend before the line jqXHR.fail( s.error ) that installs
the option callbacks, so an abort from beforeSend never reaches an error: option. It does
reach a .fail() chained by the caller. Since realtime-map.js chains .fail() while
ajaxHelper passes error: as an option, the same simulation exercises one file and not the
other. Verified empirically on jQuery 3.7.1.
Keep the window visible throughout, otherwise the Visibility.hidden() branch of the map
skips the request instead of issuing it and the test proves nothing.
Matomo version
5.13.0 (code also checked on 6.x-dev, unchanged)
PHP version
8.4.24
Server operating system
Debian GNU/Linux 13 (trixie), official matomo:5-apache Docker image
What browsers are you seeing the problem on?
Safari
Computer operating system
macOS 26.6.2
Relevant log output
Validations
- Read our Contributing Guidelines.
- Follow our Security Policy.
- Check that there isn't already an issue that reports the same bug to avoid creating duplicates.
- The provided steps to reproduce is a minimal reproducible of the Bug.
Source: matomo-org/matomo