Dépannage
Tous les cas ci-dessous ont été rencontrés pendant la mise au point du POC, pas imaginés.
« L'événement part, le fournisseur répond 200, rien n'arrive »
Le plus fréquent. Dans l'ordre :
-
User-Agent. Umami et Rybbit filtrent les robots et répondent succès en jetant l'événement. Umami n'écrit rien ; Rybbit range dans
bot_events. Un User-Agent contenant+httpsuffit à déclencher le filtre. Vérifier :Code -
Export différé. Journaux et traces partent par lots : interroger immédiatement renvoie un résultat vide. Attendre et réinterroger, jusqu'à 20 secondes.
-
Mauvais flux. Les traces OpenObserve sont dans
traces/default, pas sous le nom du span.
Aucun journal dans OpenObserve, aucune erreur
NodeSDK n'enregistre pas le fournisseur de journaux global. Diagnostic :
Code
ProxyLogger signale le problème, Logger que tout va bien. startObservability appelle
logs.setGlobalLoggerProvider() : si la régression revient, c'est là qu'il faut chercher.
Pour isoler le SDK du reste de la chaîne, envoyer un journal OTLP brut au collecteur :
Code
Si ce journal arrive et pas celui du SDK, le problème est dans le SDK, pas dans le collecteur.
« Illegal invocation » : les événements partent, rien ne sort
Symptôme : window.__analytics.diagnostics() contient
vue de page non envoyée : Failed to execute 'fetch' on 'Window': Illegal invocation,
et aucune requête réseau n'est émise.
Cause : fetch stocké en champ de classe puis appelé par this.fetchImpl(...) reçoit l'instance
de l'adaptateur comme receveur. Le navigateur refuse. Les adaptateurs détachent donc la référence
avant l'appel (const send = this.fetchImpl; await send(...)).
Attention au diagnostic : appeler globalThis.fetch déréférencé en fonction nue fonctionne,
c'est l'appel en méthode qui échoue. Un test qui ne reproduit pas la forme d'appel réelle
conclut à tort que tout va bien. Un test de non-régression couvre ce cas
(tests/unit/analytics/core.test.ts).
Le composant d'analytics ne se monte pas du tout
Symptôme : aucune requête vers les fournisseurs, aucune erreur visible, et window.__analytics
absent alors que NEXT_PUBLIC_ANALYTICS_DEBUG=true.
Vérifier d'abord que l'hydratation n'est pas cassée : un seul chunk JavaScript en échec suffit à interrompre toute la page, et les composants montés après ne s'exécutent jamais.
Code
Rencontré pendant la mise au point : un chunk référencé par le HTML mais absent de la sortie de
build, servi en HTTP 500 avec un type MIME text/plain. La console du navigateur affiche alors
« Refused to execute script … MIME type is not executable ».
Cause probable : des reconstructions successives dans le même dossier .next-<instance> laissant
un cache incohérent. Correctif :
Code
Nettoyer le dossier de build avant une reconstruction après changement de variables
NEXT_PUBLIC_* évite ce cas.
Les requêtes partent en 200, les tableaux de bord restent vides
Symptôme : le test de bout en bout voit des requêtes d'ingestion acceptées, et les fournisseurs ne comptent rien.
Deux causes, souvent confondues :
-
Le navigateur de test est pris pour un robot. Le User-Agent par défaut de Chromium sans interface contient
HeadlessChrome. Umami répond alors200avec le corps{"beep":"boop"}et ne stocke rien ; Rybbit range l'événement dansbot_events. Vérification directe :Codesmoke-app.tsremplaceHeadlessChromeparChromedans le contexte Playwright. -
La lecture de vérification est fausse.
GET /api/sites/{id}/events/countde Rybbit renvoie un tableau de tranches horaires, pas un total : il faut sommerpageview_count. Lu comme un nombre, il vaut zéro en permanence, sans erreur.
Règle générale : un test qui conclut « rien n'est arrivé » doit d'abord être mis en doute lui-même, en interrogeant le fournisseur à la main.
La recherche affiche « index non construit » alors que l'index existe
Symptôme : /pagefind/<instance>/pagefind.js répond 404, mais le fichier est bien là sur le
disque. Redémarrer le serveur suffit à tout remettre en ordre.
Cause : next start fige la liste des fichiers de public/ au démarrage. Or pnpm build:<instance>
supprime puis réécrit public/pagefind/<instance>/ après la construction des pages, et
l'écriture de 110 Mo prend une bonne minute. Un serveur démarré pendant cette fenêtre sert des
404 jusqu'à son redémarrage — et la page de recherche affiche un message qui accuse le build.
Attendre la fin complète du script, pas la ligne « Indexed … pages » de Pagefind : elle précède l'écriture.
Un événement métier manque, les vues de page sont là
Les vues de page sont vidées à l'enfilement ; les autres événements attendent l'échéance de
la file, 5 s par défaut (flushIntervalMs). Un événement émis juste avant une navigation
part donc au vidage déclenché par le masquage de l'onglet, pas avant.
Conséquence pour un test : fermer le navigateur moins de 5 s après le geste mesure l'empressement
du test, pas la chaîne. smoke-app.ts laisse passer l'échéance.
Conséquence pour la production : sur un site à chargements complets, ce vidage de dernière chance
repose sur visibilitychange et sur keepalive. C'est une livraison « au mieux », assumée.
Matomo répond « Unable to authenticate with the provided token »
Le jeton d'API de infra/analytics/compose/.env a expiré. En régénérer un :
Code
puis remplacer MATOMO_TOKEN_AUTH. Le symptôme trompe : le test de fumée annonce « aucun
événement retrouvé », alors que les événements sont bien stockés.
Matomo reste sur l'écran d'installation
core:install n'existe pas en Matomo 5. Lancer node infra/analytics/scripts/provision-matomo.mjs.
Vérifier que le schéma est créé :
Code
31 tables attendues. Le client en ligne de commande s'appelle mariadb, pas mysql.
L'API Rybbit répond MISSING_OR_NULL_ORIGIN
better-auth exige un en-tête Origin et un cookie de session. Un jeton Bearer ne suffit pas
pour l'API d'administration — il ne sert que pour /api/track.
Le compose ne se valide pas
Cette machine n'a que docker-compose v1.29. Les fichiers évitent la syntaxe propre à v2.
node infra/analytics/scripts/stack.mjs config détecte la version disponible.
Rien ne démarre
C'est voulu : aucun profil, aucun service. Préciser un profil.
Code
Le test de fumée dit « ignoré »
Service éteint ou identifiant absent de compose/.env. Lancer le script de provisionnement
correspondant. « Ignoré » ne fait pas échouer le test : c'est une capacité non vérifiée, pas un
échec.