¿Hermes acaba de pedirte que superes una comprobación de navegador? Esto es qué es el reto 428 en el free tier


Son las dos de la mañana. Tu cron job se ejecuta en un servidor, usando el free tier para una ronda de investigación. No hay ningún error en los logs, solo un enlace que alguien imprimió, y luego el trabajo falla en silencio. Por la mañana lo lees y no tienes ni idea de qué era ese enlace, por qué apareció ni si se supone que tenías que hacer clic.

No hay nada roto en tu setup. El free tier simplemente ahora tiene una puerta delante. El PR #133824, fusionado el 6 de octubre, enseña a Hermes a manejar bien esa ruta — y, más importante, se asegura de que nunca se quede ahí esperando cuando no hay nadie a quien esperar.

Cuándo aparece la puerta

La inferencia anónima gratuita pasa por POST /api/anonymous/token para un intercambio de token. El portal se puede configurar para exigir una comprobación de navegador desde rangos de IP o países concretos antes de entregar capacidad anónima. Cuando se activa una regla así, ese endpoint responde HTTP 428 con el código challenge_required y una URL del portal.

Lo importante: esto es política del lado del portal, ajustable en cualquier momento sin un release de Hermes. Así que “la semana pasada funcionaba bien” normalmente no tiene nada que ver con tu máquina.

Una primitiva, tres pasos

Hermes implementa exactamente una primitiva para esto, llamada browser-v1:

  1. abrir la URL que entregó el portal;
  2. hacer polling de /api/anonymous/challenge/status hasta que se despeje;
  3. intercambiar por un token de nuevo.

Todo lo que hace la página en sí — detección de bots, proof of work en el navegador, un fallback interactivo, todo su texto — pertenece al portal y puede cambiar sin que tú actualices nada. Y el mint sigue siendo la autoridad: Hermes nunca decide en local que una comprobación pasó.

El intercambio envía un bloque client auto-declarado (superficie, versión, plataforma, más capabilities: ["browser-v1"]) y un user agent hermes-agent/<version>.

Quién abre la ventana

El comportamiento difiere por superficie, que es la respuesta a “por qué no vi nada”:

  • Desktop: ese proceso no abre nada por sí mismo. Publica el challenge (un evento global free_tier.challenge, más el campo challenge en free_tier.status para un cliente que se conecte después); el renderer se lo pasa al proceso principal de Electron, que lo carga en una ventana oculta, en sandbox y con origen fijado. Esa ventana solo se revela si la página pide explícitamente un humano.
  • Terminal: imprime el enlace y ábrelo en el navegador del sistema cuando haya uno gráfico.
  • La espera corre fuera de los locks: el intercambio que chocó con el 428 ya desenrolló su excepción fuera de los bloques with, así que una página lenta nunca bloquea a un profile o proceso hermano. Se trabaja un challenge a la vez por proceso; un segundo hilo que choca con el mismo 428 espera al primero y luego simplemente intercambia de nuevo.

Cuándo no te va a colgar de ninguna manera

Los puntos más arriesgados estaban en la primera versión de este trabajo, y arreglarlos es la mayor parte de lo que hace este PR. Todos son formas conocidas:

  • Un gateway nunca espera. Los gateways resuelven las credenciales de Nous de forma síncrona desde código asíncrono, así que un 428 aparcaba el event loop hasta 120 segundos — y nadie se sienta en la consola de un bot a superar una comprobación de navegador. La superficie del gateway ahora registra, anuncia y lanza un error reintentable de inmediato.
  • El adaptador de proxy no bloquea el lock. Resuelve las credenciales mientras tiene el lock en el que hacen cola todas las peticiones proxeadas, así que una pausa de 120 segundos lo bloqueaba todo. Ahora resuelve como llamador en segundo plano.
  • Los lectores en segundo plano nunca abren nada. Los ticks de keepalive y las pintadas de estado reciben el challenge pero nunca se bloquean, ni imprimen, ni abren un navegador.
  • La TUI stdio por fin te avisa. Antes solo guardaba el stderr del gateway hijo como log, así que un challenge se convertía en un cuelgue silencioso de 120 segundos sin enlace. Los challenges obligatorios en primer plano ahora se anuncian por JSON-RPC y la TUI imprime el enlace.

Obligatorio y opcional son cosas distintas

Un challenge también puede llegar en un intercambio correcto con required: false — el servicio está midiendo, no imponiendo. Ese solo se anuncia a un cliente de desktop (para que una ventana oculta pueda despejarlo antes); nunca se abre en tu navegador y nada espera por él.

Un challenge obligatorio sí hace esperar a una superficie interactiva: hasta 120 segundos por intento, lo que acota el caso de “un humano resolviendo un captcha” sin aparcar una petición durante los diez minutos completos del ticket. Un anuncio fallido (por ejemplo, un problema en la salida estándar) cae a imprimir el enlace en vez de perderlo y hacer fallar la ejecución.

Qué pasa cuando no se despeja

  • Un challenge que nunca se despeja termina con un mensaje reintentable y un cooldown de fail-fast en vez de reintentar sin fin.
  • Un segundo challenge_required no entra en bucle — se expone como un error reintentable con una explicación. Eso es deliberado: un bucle sería peor que un fallo.
  • Un código de error pow_* en un estado distinto de 428 conserva su significado original (ya no se trata como error de servidor reintentable en todos los endpoints), así que los flujos de registro y promoción no se ven afectados.

Qué hacer al respecto

Si tu máquina está desatendida (un servidor, un contenedor, CI):

  • abre ese enlace en tu navegador y supera la comprobación; el ticket pertenece a ese intercambio, así que deja que Hermes reintente después.
  • si esto sigue pasando, considera ejecutar el trabajo programado sobre la capacidad de una cuenta de Nous con sesión iniciada en vez del free tier anónimo — la ruta de cuenta no pasa por la comprobación anónima. Mira este artículo sobre la ruta de búsqueda gratuita para los diagnósticos relacionados.
  • En desktop, no hagas nada: la ventana oculta se encarga en segundo plano y solo aparece si te necesita.

La versión corta

La comprobación no es un bug; es la política del portal haciendo su trabajo. Las responsabilidades de Hermes son estrechas a propósito: poner el enlace delante de ti, no bloquear nunca donde no hay nadie mirando, y no concluir jamás en local que una comprobación pasó. Una vez que conoces ese reparto de tareas, un enlace en tus logs es un arreglo de cinco segundos en vez de una mañana perdida.

Si prefieres no depender del free tier en absoluto, compara cinco canales de búsqueda gratuitos.