Rétrospective d’un incident sur la chaîne de publication via le navigateur OpenClaw : de fields are required à la réparation système d’un stale ref
Cet article est une rétrospective complète d’un dépannage réel en production. L’objectif est d’expliquer clairement « pourquoi ça a cassé, pourquoi ça marchait avant, et qu’est-ce qui a été modifié cette fois », et de fournir des étapes de correction reproductibles.
Public concerné :
- Ceux qui utilisent l’outil browser dans OpenClaw pour automatiser la publication / le remplissage de formulaires
- Ceux qui ont déjà rencontré
fields are required,Element \"eXX\" not found or not visible,No tool call found for function call output ... - Ceux qui veulent faire évoluer un “correctif d’urgence” en “solution stable et réutilisable”
I. Symptômes et impact métier
1) Principales erreurs
Lors de cet incident, trois erreurs typiques sont apparues :
fields are requiredElement \"e92\" not found or not visible. Run a new snapshot to see current page elements.400 No tool call found for function call output with call_id ...
2) Comportement côté métier
- La page s’ouvre
- Le DOM peut être snapshot
- Dès qu’on arrive à
act/fillou à une action de saisie sur un nœud, le service de contrôle browser renvoie une erreur et s’interrompt - La chaîne de publication multi-sites (Linux.do / V2EX / 2libra / iSharkFly) ne peut plus s’exécuter en continu
Ce type de panne est facile à confondre avec un “problème de permissions du compte” ou un “contexte trop long”, mais cette fois-ci a prouvé que ce n’était pas le cas.
II. Chronologie (jalons clés)
- Vers 2026-02-23 12:44 (CST) : installation/mise à jour locale d’OpenClaw vers
2026.2.22-2 - Ensuite, de nombreuses erreurs browser :
fields are required - En poussant plus loin : apparition d’un stale ref :
Element \"e92\" not found or not visible - Dans l’historique des sessions :
No tool call found for function call output ... - Finalement : reprise de la publication réussie après compatibilité de protocole + contournement stale ref
Remarque :
No tool call found ...etfields are requiredne sont pas le même problème.- Réduire la fenêtre de contexte (par ex. 1048576 → 200000) ne corrige pas directement ces deux erreurs de bas niveau.
III. Décomposition des causes racines
Cause racine A : incompatibilité du protocole fill (déclencheur initial)
La forme courante des requêtes d’action en amont est :
{
"kind": "fill",
"ref": "e57",
"text": "..."
}
Alors que l’implémentation actuelle du routage tend à exiger :
{
"kind": "fill",
"fields": [
{ "ref": "e57", "type": "text", "value": "..." }
]
}
Quand fields n’est pas fourni et qu’il n’y a pas de mapping de compatibilité, cela déclenche directement fields are required.
Cause racine B : pages dynamiques entraînant une dérive de ref (stale ref)
Par exemple :
- lors du snapshot, on obtient
e92 - après un repaint de composant / un changement de couche (overlay),
e92n’est plus valide - l’action
type/fillsuivante réutilise l’ancien ref et déclenchenot found or not visible
C’est très fréquent dans des UI dynamiques comme le champ de sélection de nœud sur V2EX.
Cause racine C : No tool call found ... = désalignement de l’état d’appel session/tool-call
Cette erreur relève d’une incohérence de la chaîne session/tool-call (call_id ne correspond pas), et non d’un échec intrinsèque des opérations DOM du navigateur.
IV. Objectifs et stratégie de correction
L’objectif n’est pas un “patch ponctuel”, mais de rendre la chaîne de publication “compatible + auto-guérissante + observable” :
- Compatibilité avec les anciennes formes de requêtes, pour éviter
fields are required - Récupération automatique des stale ref, sans exiger un resnapshot manuel à chaque fois
- Un contournement même en cas de second échec, afin que le flux ne s’effondre pas au point d’écriture critique
V. Modifications réelles (dist à l’exécution)
Remarque : après le packaging, OpenClaw génère plusieurs artefacts hashés ; il faut combler les branches clés de manière synchronisée pour éviter qu’au runtime un bundle non corrigé soit utilisé.
1) Couche de compatibilité fill
Dans le case \"fill\" de /act, ajout d’un mapping de compatibilité :
- lorsque
fieldsest absent, conversion automatique de{ref,text/value}versfields:[{ref,type:\"text\",value}] - et fourniture d’une valeur par défaut
textpour letypedu champ
2) Retry automatique sur stale ref
Dans case \"type\" et case \"fill\" :
- capture de
Unknown ref/not found or not visible - exécution automatique d’un
snapshotRoleViaPlaywright({ refsMode: \"aria\" }) - puis retry de l’action initiale
3) Deuxième niveau de contournement (amélioration clé de cette fois)
Si “resnapshot + retry” échoue encore à cause d’un stale ref :
- pour
type: tentative d’écriture directe dansdocument.activeElementet dispatch deinput/change - pour
fill: dans le cas d’un seul champ texte, même contournement via activeElement
Cela couvre le scénario fréquent “le focus est toujours sur l’input cible, mais l’ancien ref est devenu invalide”.
4) Fichiers concernés
/opt/homebrew/lib/node_modules/openclaw/dist/routes-CmNAokG-.js/opt/homebrew/lib/node_modules/openclaw/dist/routes-FGJF5gtZ.js/opt/homebrew/lib/node_modules/openclaw/dist/pi-embedded-helpers-CNhhELVT.js/opt/homebrew/lib/node_modules/openclaw/dist/pi-embedded-helpers-DxTyisc4.js
VI. Étapes de validation (reproductibles)
- Redémarrer le gateway et confirmer que le nouveau processus est actif (PID changé)
- Déclencher le même flux d’auto-publication sur le même chemin
- Observer si les logs contiennent encore :
fields are requiredElement \"eXX\" not found or not visible
- Vérifier le résultat métier : le post a-t-il été réellement créé avec succès ?
Résultat cette fois :
- Le chemin en panne a été rétabli, publication réussie.
VII. Pourquoi “c’était OK avant-hier, et cette fois il faut autant modifier” ?
La conclusion est très claire :
-
Le changement de version a amplifié les différences de protocole
- Version locale actuelle :
[email protected] - Dans cette version, le point d’entrée
fillest plus strict sur la formefields[]
- Version locale actuelle :
-
Le même problème doit être comblé dans plusieurs entrées dist
- Ça donne l’impression de “modifier beaucoup de fichiers”, mais en réalité “la même logique existe en doublon dans plusieurs artefacts packagés”
-
La dérive de ref sur pages dynamiques est un risque naturel
- Ne pas être tombé dessus avant ne veut pas dire que ça n’existait pas
- Dès que les repaints deviennent plus fréquents, ça explose en série
Donc cette fois, ce n’est pas un “pur problème de configuration”, mais bien un manque simultané en “compatibilité de protocole + stabilité UI dynamique”.
VIII. Recommandations (prévention de régression)
1) Recommandations côté protocole
- Définir explicitement le schéma canonical de
filldans le protocole des actions browser - Conserver une fenêtre de rétrocompatibilité pour l’ancien schéma, et logger une indication de migration
2) Recommandations côté exécution
- Ajouter un interrupteur configurable pour un snapshot automatique en amont de
type/fill/click(mode haute stabilité) - Ajouter des logs structurés sur la branche de retry stale-ref (pour confirmer si le contournement a été déclenché)
3) Recommandations côté exploitation
- Après chaque upgrade, exécuter un E2E minimal : open → snapshot → fill → submit
- Brancher des alertes sur les erreurs clés (
fields are required,Unknown ref)
4) Recommandations côté session
- Traiter
No tool call found ...séparément (intégrité de session / cohérence de relecture), sans le mélanger aux problèmes DOM du navigateur
IX. Checklist de dépannage (pour moi-même dans le futur)
En cas de problème similaire, suivre cet ordre :
- D’abord séparer les types d’erreurs (protocole / DOM / session)
- Vérifier le timestamp des derniers logs pour éviter de mal diagnostiquer sur une ancienne erreur
- Valider que la forme du payload de requête correspond à la version actuelle
- Ajouter “retry avec snapshot + contournement activeElement” pour les stale ref
- Redémarrer et confirmer que le nouveau processus a chargé le nouveau code
- Re-tester sur le même chemin, confirmer le succès métier et pas seulement la disparition de l’erreur
X. Conclusion
Cette correction ne consiste pas à “cacher l’erreur”, mais à compléter la chaîne de publication avec trois niveaux de résilience :
- Niveau 1 : compatibilité de protocole (éviter l’inadéquation de structure)
- Niveau 2 : récupération automatique (retry après snapshot)
- Niveau 3 : contournement de saisie (écriture via activeElement)
L’objectif final est unique : permettre à l’automatisation de rester durable, reproductible et maintenable sur de vraies pages web dynamiques.
Si vous faites aussi de l’automatisation navigateur avec OpenClaw, je recommande de figer directement ces trois niveaux de stratégie comme modèle par défaut.