Hermes vient de vous demander de passer un contrôle navigateur ? Voici ce qu'est le challenge 428 sur le free tier


Il est deux heures du matin. Votre cron job tourne sur un serveur, utilisant le free tier pour une session de recherche. Aucune erreur dans les logs — juste un lien que quelqu’un a affiché, puis le job échoue discrètement. Le matin, vous le lisez sans avoir la moindre idée de ce qu’était ce lien, pourquoi il est apparu, ni si vous étiez censé cliquer dessus.

Rien dans votre configuration n’est cassé. Le free tier a simplement désormais une porte devant lui. La PR #133824, fusionnée le 6 octobre, apprend à Hermes à gérer ce chemin correctement — et, plus important, fait en sorte qu’il ne reste jamais planté à attendre quand il n’y a personne pour attendre.

Quand la porte apparaît

L’inférence anonyme gratuite passe par POST /api/anonymous/token pour un échange de token. Le portal peut être configuré pour exiger un contrôle navigateur depuis des plages d’IP ou des pays choisis avant d’accorder de la capacité anonyme. Quand une telle règle se déclenche, cet endpoint répond HTTP 428 avec le code challenge_required et une URL de portal.

Le point important : il s’agit d’une politique côté portal, ajustable à tout moment sans release de Hermes. Donc « ça marchait très bien la semaine dernière » n’a en général rien à voir avec votre machine.

Une primitive, trois étapes

Hermes implémente exactement une primitive pour cela, appelée browser-v1 :

  1. ouvrir l’URL que le portal a transmise ;
  2. interroger /api/anonymous/challenge/status jusqu’à ce qu’elle se débloque ;
  3. échanger à nouveau pour obtenir un token.

Tout ce que fait la page elle-même — détection de bot, proof of work dans le navigateur, un fallback interactif, tous ses textes — appartient au portal et peut changer sans que vous mettiez à jour quoi que ce soit. Et la mint reste l’autorité : Hermes ne décide jamais localement qu’un contrôle est passé.

L’échange envoie un bloc client auto-déclaré (surface, version, platform, plus capabilities: ["browser-v1"]) et un user agent hermes-agent/<version>.

Qui ouvre la fenêtre

Le comportement diffère selon la surface, ce qui répond à « pourquoi je n’ai rien vu » :

  • Desktop : ce processus n’ouvre rien lui-même. Il publie le challenge (un événement global free_tier.challenge, plus le champ challenge sur free_tier.status pour un client qui se connecte plus tard) ; le renderer le transmet au processus principal Electron, qui le charge dans une fenêtre cachée, sandboxée et épinglée à son origine. Cette fenêtre n’est révélée que si la page demande explicitement un humain.
  • Terminal : afficher le lien, et l’ouvrir dans le navigateur système quand il y en a un de graphique.
  • L’attente tourne hors des locks : l’échange qui a reçu le 428 a déjà dépilé son exception hors des blocs with, donc une page lente ne bloque jamais un profile ou un processus frère. Un seul challenge est traité à la fois par processus ; un second thread qui reçoit le même 428 attend le premier puis échange simplement à nouveau.

Quand ça ne vous bloquera absolument pas

Les endroits les plus risqués étaient dans la première version de ce travail, et les corriger représente l’essentiel de ce que fait cette PR. Ce sont tous des formes familières :

  • Une gateway n’attend jamais. Les gateways résolvent les credentials Nous de façon synchrone depuis du code async, donc un 428 immobilisait l’event loop jusqu’à 120 secondes — et personne ne reste assis devant la console d’un bot pour passer un contrôle navigateur. La surface gateway enregistre désormais, annonce et lève immédiatement une erreur réessayable.
  • L’adaptateur proxy ne bloque pas le lock. Il résolvait les credentials en gardant le lock sur lequel toutes les requêtes proxied font la queue, donc une pause de 120 secondes bloquait tout. Il se résout désormais comme un appelant en arrière-plan.
  • Les lecteurs en arrière-plan n’ouvrent jamais rien. Les ticks keepalive et les affichages de statut reçoivent le challenge mais ne bloquent, n’affichent ni n’ouvrent jamais de navigateur.
  • Le TUI stdio vous le dit enfin. Il gardait auparavant le stderr du child gateway comme simple log, donc un challenge devenait un blocage silencieux de 120 secondes sans lien. Les challenges requis au premier plan sont désormais annoncés via JSON-RPC et le TUI affiche le lien.

Requis et optionnel, ce n’est pas la même chose

Un challenge peut aussi arriver sur un échange réussi avec required: false — le service mesure, il n’impose rien. Celui-là n’est annoncé qu’à un client desktop (afin qu’une fenêtre cachée puisse le passer tôt) ; il n’est jamais ouvert dans votre navigateur et rien ne l’attend.

Un challenge requis fait bien attendre une surface interactive : jusqu’à 120 secondes par tentative, ce qui borne le cas « un humain résout un captcha » sans immobiliser une requête pendant les dix minutes complètes du ticket. Une annonce échouée (par exemple un problème sur la sortie standard) retombe sur l’affichage du lien plutôt que de le perdre et de faire échouer le run.

Ce qui se passe quand ça ne se débloque pas

  • Un challenge qui ne se débloque jamais se termine avec un message réessayable et un cooldown fail-fast au lieu de réessayer sans fin.
  • Un second challenge_required n’est pas rebouclé — il remonte comme une erreur réessayable avec une explication. C’est délibéré : une boucle serait pire qu’un échec.
  • Un code d’erreur pow_* sur un statut autre que 428 garde son sens d’origine (il n’est plus traité comme une erreur serveur réessayable sur tous les endpoints), donc les flux d’inscription et de promotion ne sont pas affectés.

Quoi faire face à ça

Si votre machine est sans surveillance (un serveur, un conteneur, la CI) :

  • ouvrez ce lien dans votre navigateur et passez le contrôle ; le ticket appartient à cet échange, donc laissez Hermes réessayer ensuite.
  • si cela arrive sans arrêt, envisagez d’exécuter vos tâches planifiées sur la capacité d’un compte Nous connecté plutôt que sur le free tier anonyme — le chemin du compte ne passe pas par le contrôle anonyme. Voir cet article sur la route de recherche gratuite pour les diagnostics associés.
  • Sur desktop, ne faites rien : la fenêtre cachée s’en occupe en arrière-plan et n’apparaît que si l’on a besoin de vous.

En bref

Le contrôle n’est pas un bug ; c’est la politique du portal qui fait son travail. Les responsabilités de Hermes sont volontairement étroites : mettre le lien devant vous, ne jamais bloquer là où personne ne regarde, et ne jamais conclure localement qu’un contrôle est passé. Une fois cette répartition des rôles comprise, un lien dans vos logs devient une correction de cinq secondes plutôt qu’une matinée perdue.

Si vous préférez ne pas dépendre du free tier du tout, comparez cinq channels de recherche gratuits.