Um navegador na nuvem com rate limit não derruba mais o browser_exec


Você configurou um navegador na nuvem para o Hermes tirar um print do seu dashboard toda manhã e jogar num canal. Funcionou a semana inteira e, numa manhã, em vez do gráfico você recebe um erro: returned no CDP endpoint, so Browser Use mode cannot drive it. A página está bem. Seu script está bem. O serviço de navegador na nuvem estava aplicando rate limit por um instante — e toda a tarefa de navegador morreu junto.

O mais estranho: as ferramentas browser_* integradas do Hermes continuaram funcionando exatamente nas mesmas condições. Só o browser_exec caiu.

Duas formas pelas quais o navegador travava

Os dois sintomas vêm da mesma coisa. Depois que um navegador na nuvem é configurado (browser.cloud_provider, escolhido entre browserbase, browser-use, camofox, nous ou local), ainda deveria haver um caminho local disponível na máquina — mas o browser_exec não chegava até ele.

Um: a criação da sessão falha, a chamada falha

Quando o provedor na nuvem falhava na criação da sessão, o browser_exec falhava de vez:

Cloud browser provider BrowserUseBrowserProvider returned no CDP endpoint,
so Browser Use mode cannot drive it. Switch to the built-in browser tools
for this provider.

A falha vista ao vivo foi um rate limit: o gateway respondeu 429 RATE_LIMIT_EXCEEDED, com retryAfter 17 e limit 200.

A causa raiz é que o browser_exec e as ferramentas integradas não seguiam o mesmo caminho. As ferramentas de navegador integradas já recorrem ao Chromium local empacotado quando não conseguem criar uma sessão local, marcando a sessão como fallback_from_cloud. O browser_exec só lia cdp_url dessa sessão — e uma sessão local não tem cdp_url até o Chromium dela iniciar. Então ele lançava o erro acima e culpava o provedor.

Há também um amplificador: a sessão que falhou fica em cache. Chamadas seguintes com a mesma session key continuavam batendo na mesma sessão quebrada até o reaper de inatividade removê-la. Um único 429 podia derrubar os minutos seguintes de trabalho com o navegador.

O ajuste é deliberadamente pequeno. Em tools/browser_use_cli.py::_resolve_backend_cdp, quando a sessão do provedor volta como fallback_from_cloud, resolva o endpoint CDP do Chromium empacotado do mesmo jeito que o caminho sem provedor faz, e registre a falha do provedor uma vez só. Um provedor que devolve uma sessão sem CDP URL e sem fallback ainda falha com a mesma mensagem — nada finge funcionar.

Dois: o navegador na nuvem não alcança seu localhost

O segundo sintoma é mais comum: você tem um servidor de dev nesta máquina, pede http://localhost:3000 e recebe:

Blocked: URL targets a private or internal address

O browser_exec pré-analisa as URLs do seu código por segurança, mas chamava essa checagem sem o veredito do roteamento híbrido. Com cloud_provider definido, o backend conta como não local, então toda URL privada era rejeitada.

O browser_navigate nunca teve esse problema — ele roteia URLs privadas para um sidecar local. Dois caminhos dentro de um mesmo subsistema de navegador, dois comportamentos diferentes; esta mudança os alinha.

Qual URL vai para onde

Endereço que você acessa Quem abre
https://example.com o navegador na nuvem configurado
http://localhost:3000 sidecar local de Chromium sob a chave de cache ::local
http://192.168.1.9 (LAN) sidecar local de Chromium
169.254.169.254 (metadados da nuvem) bloqueado incondicionalmente, sem backend
uma chamada que mistura URLs públicas e privadas a chamada inteira roda local

Alguns detalhes de implementação importam porque são essenciais para a segurança:

  • O predicado de rota _hybrid_routes_locally(url) agora é compartilhado por browser_navigate e browser_exec, então os dois não podem divergir;
  • Cada URL no código é avaliada uma única vez, e esse veredito decide tanto a checagem de segurança quanto a rota. Um host que resolve como privado e depois se religa a um IP público não consegue afrouxar a checagem de endereços privados e ainda assim ser enviado para a nuvem;
  • Uma chamada que mistura URLs públicas e privadas roda inteiramente local — a parte privada nunca vaza para cima;
  • O sidecar usa a chave de cache ::local e roda sob seu próprio harness daemon (BU_NAME=_local_<name>). O daemon lê seu ambiente CDP uma vez no start, então compartilhar o daemon da rota da nuvem repassaria a URL privada ao navegador na nuvem. Daemons separados, não um compartilhado;
  • Uma chamada seguinte sem literal de URL permanece na rota que a chamada anterior tomou.

O piso de segurança não se moveu

Fallbacks são um lugar fácil de introduzir um furo, então todas as invariantes existentes foram mantidas:

  • Endereços de metadados da nuvem continuam bloqueados incondicionalmente: 169.254.169.254 ainda responde “URL targets a cloud metadata endpoint”, independentemente do provedor;
  • browser.auto_local_for_private_urls vem ligado por padrão; colocá-lo em false ainda rejeita URLs privadas, a menos que você também defina browser.allow_private_urls, o que deixa o provedor na nuvem tentar — geralmente em vão, já que Browserbase e companhia não alcançam sua LAN;
  • Um override de CDP não é tratado como local: se você definir browser.cdp_url ou usar /browser connect, o roteamento híbrido retorna falso e o comportamento segue igual;
  • Um redirecionamento de público para privado é recusado, não vazado;
  • A rechecagem da URL final após a execução não foi tocada.

O fallback local precisa do sidecar local — a mesma CLI agent-browser que o modo puramente local usa. hermes setup tools → Browser Automation instala para você.

Status e atualização

Os dois ajustes (PRs #136447 e #136442) foram mesclados na main em 2026-10-11. A tag atual, v0.21.6 de 8 de outubro, não os inclui; a próxima release incluirá. Para usá-los hoje, atualize a partir da main.

Depois de atualizar, dá para confirmar que o fallback entrou procurando aquela única linha de falha do provedor no log — ela aparece uma vez, e a chamada do navegador segue no Chromium local.

Para fechar

Um navegador na nuvem é rápido e prático, mas é um serviço externo: aplica rate limit e sai do ar. A configuração que realmente se sustenta é nuvem primeiro, local como piso, e endereços sensíveis que nunca saem da máquina. Esse piso é o que estas mudanças restauram: a queda de um provedor não encerra mais sua tarefa, servidores de dev e páginas da LAN abrem como antes, e nem endereços internos nem endpoints de metadados da nuvem chegaram perto da nuvem.

Leitura relacionada: como as ferramentas de navegador integradas viraram o padrão explica a escolha de provedor, o orçamento de snapshots do navegador trata de outro tipo de “o navegador está lento”, e os desafios do navegador no plano gratuito cobre os trade-offs de rodar um navegador na nuvem com orçamento apertado.