Postmortem de la falla del flujo de publicación del navegador en OpenClaw: de fields are required a stale ref, una corrección a nivel de sistema
Este artículo es una retrospectiva completa de una resolución de incidentes real en producción. El objetivo es explicar claramente “por qué explotó, por qué antes no había problema, y qué se cambió exactamente esta vez”, y dar pasos de corrección repetibles.
Público objetivo:
- Quienes usan la herramienta browser en OpenClaw para automatizar publicaciones/rellenar formularios
- Quienes se han topado con
fields are required,Element \"eXX\" not found or not visible,No tool call found for function call output ... - Quienes quieren convertir un “apagafuegos temporal” en una “solución de corrección estable y reutilizable”
I. Síntomas e impacto en el negocio
1) Errores principales
En este incidente aparecieron tres tipos de errores típicos:
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) Comportamiento en negocio
- La página puede abrirse
- Se puede hacer snapshot del DOM
- En cuanto se llega a
act/fillo a una acción de entrada sobre un nodo, el servicio de control del browser falla y se interrumpe - Hace que el flujo de publicación cross-site (Linux.do / V2EX / 2libra / iSharkFly) no pueda ejecutarse de forma continua
Este tipo de fallas es fácil de malinterpretar como “problema de permisos de la cuenta” o “contexto demasiado largo”, pero en esta ocasión se demostró que no era eso.
II. Línea de tiempo (hitos clave)
- Aproximadamente 2026-02-23 12:44 (CST): instalación/actualización local de OpenClaw a
2026.2.22-2 - Después aparecen muchos errores del browser:
fields are required - Al avanzar más, aparece stale ref:
Element \"e92\" not found or not visible - En sesiones históricas existe:
No tool call found for function call output ... - Finalmente se recuperó la publicación tras aplicar compatibilidad de protocolo + mitigación (fallback) para stale ref
Aclaración:
No tool call found ...yfields are requiredno son el mismo problema.- Reducir la ventana de contexto (por ejemplo 1048576 → 200000) no corrige directamente estos dos errores de base.
III. Desglose de causas raíz
Causa raíz A: incompatibilidad del protocolo de fill (lo que primero detona)
La forma común de la solicitud de acción upstream es:
{
"kind": "fill",
"ref": "e57",
"text": "..."
}
Y la implementación actual del enrutado tiende a exigir:
{
"kind": "fill",
"fields": [
{ "ref": "e57", "type": "text", "value": "..." }
]
}
Cuando no se proporciona fields y no hay mapeo de compatibilidad, se dispara directamente fields are required.
Causa raíz B: páginas dinámicas provocan deriva de ref (stale ref)
Por ejemplo:
- En el snapshot se obtiene
e92 - Tras un redraw del componente/cambio de capa modal,
e92ya no es válido - El
type/fillposterior sigue ejecutándose con el ref antiguo y disparanot found or not visible
Esto es muy común en UIs dinámicas como el cuadro de entrada de selección de nodos en V2EX.
Causa raíz C: No tool call found ... es un desajuste del estado de llamada de sesión
Ese error corresponde a una inconsistencia en la cadena session/tool-call (el call_id no coincide), y no a un fallo de la operación del DOM del navegador en sí.
IV. Objetivos y estrategia de corrección
El objetivo no es un “parche puntual”, sino convertir el flujo de publicación en “compatible + autorrecuperable + observable”:
- Compatibilizar la forma antigua de la solicitud para evitar
fields are required - Recuperación automática ante stale ref, sin exigir un re-snapshot manual cada vez
- Un fallback de segunda capa si el segundo intento falla, para que el flujo no se caiga justo en el punto crítico de escritura
V. Cambios reales (dist en runtime)
Aclaración: tras empaquetar OpenClaw existen múltiples artefactos hash; hay que completar sincrónicamente las ramas clave para evitar que en runtime se ejecute un bundle no parcheado.
1) Capa de compatibilidad de fill
En el case \"fill\" de /act se añadió un mapeo de compatibilidad:
- Cuando falta
fields, convertir automáticamente{ref,text/value}afields:[{ref,type:\"text\",value}] - Y dar a
typedel field un valor por defectotext
2) Reintento automático para stale ref
En case \"type\" y case \"fill\":
- Capturar
Unknown ref/not found or not visible - Ejecutar automáticamente una vez
snapshotRoleViaPlaywright({ refsMode: \"aria\" }) - Luego reintentar la acción original
3) Fallback de segunda capa (mejora clave de esta vez)
Si tras “re-snapshot + reintento” aún falla por stale ref:
- Para
type: intentar escribir el valor directamente endocument.activeElementy despacharinput/change - Para
fill: en escenarios de texto de un solo campo, usar igualmente el fallback de escritura en activeElement
Esto cubre el escenario frecuente de “el foco sigue en el input objetivo, pero el ref viejo ya expiró”.
4) Archivos implicados
/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. Pasos de verificación (reproducibles)
- Reiniciar el gateway y confirmar que el nuevo proceso está activo (cambio de PID)
- Disparar el mismo flujo de autopublicación por la misma ruta
- Observar si en los logs siguen apareciendo:
fields are requiredElement \"eXX\" not found or not visible
- Verificar el resultado de negocio: si la publicación realmente se creó con éxito
Resultado de esta vez:
- La ruta afectada se recuperó y la publicación fue exitosa.
VII. ¿Por qué “hace dos días iba bien y ahora hay que cambiar tanto”?
La conclusión es clara:
-
El cambio de versión amplificó las diferencias de protocolo
- Versión local actual:
openclaw@2026.2.22-2 - En esta versión, la entrada de
filles más estricta con la formafields[]
- Versión local actual:
-
El mismo problema debe completarse en múltiples entradas dist
- Parece que “se cambian muchos archivos”, pero en esencia es “la misma lógica repetida en múltiples artefactos empaquetados”
-
La deriva de ref en páginas dinámicas es un riesgo inherente
- Que antes no ocurriera no significa que no exista
- En cuanto la página redibuja más a menudo, explota de forma concentrada
Así que esta vez no es un “problema puramente de configuración”, sino una brecha simultánea de “compatibilidad de protocolo + estabilidad ante UI dinámica”.
VIII. Recomendaciones posteriores (para evitar regresiones)
1) Recomendaciones a nivel de protocolo
- Definir claramente en el protocolo de acciones del browser el canonical schema de
fill - Mantener una ventana de compatibilidad hacia atrás para el schema antiguo, y registrar en logs una guía de migración
2) Recomendaciones a nivel de ejecución
- Para
type/fill/click, añadir un switch configurable que haga snapshot automáticamente como paso previo (modo alta estabilidad) - Registrar logs estructurados en la rama de reintento por stale-ref (para confirmar si se disparó el fallback)
3) Recomendaciones a nivel de operaciones
- Tras cada upgrade, ejecutar un E2E mínimo: open → snapshot → fill → submit
- Integrar alertas para errores clave (
fields are required,Unknown ref)
4) Recomendaciones a nivel de sesión
- Investigar
No tool call found ...por separado (integridad de sesión/consistencia de replay), sin mezclarlo con problemas del DOM del browser
IX. Checklist de diagnóstico (para mi yo del futuro)
Si aparece un problema similar, seguir este orden:
- Separar primero el tipo de error (protocolo/DOM/session)
- Revisar el punto temporal de los logs más recientes para evitar diagnósticos con errores viejos
- Verificar si la forma del payload de la solicitud coincide con la versión actual
- Añadir para stale ref “reintento con snapshot + fallback a activeElement”
- Reiniciar y confirmar que el nuevo proceso cargó el nuevo código
- Reprobar con la misma ruta y confirmar éxito de negocio, no solo que desapareció el error
X. Cierre
Esta corrección no fue “ocultar el error”, sino completar el flujo de publicación con tres capas de resiliencia:
- Primera capa: compatibilidad de protocolo (evita desajustes de estructura)
- Segunda capa: recuperación automática (reintento tras snapshot)
- Tercera capa: fallback de entrada (escritura en activeElement)
El objetivo final es uno: que el flujo de automatización sea sostenible, reproducible y mantenible en páginas web dinámicas reales.
Si tú también estás haciendo automatización del navegador con OpenClaw, conviene solidificar estas tres capas como plantilla por defecto.