Skip to content

fix(websocket): answer non-GET HTTP probes instead of 502 + error flood#6

Merged
Ho1yShif merged 2 commits into
mainfrom
fix/render-webui-head-probe-502
Jul 8, 2026
Merged

fix(websocket): answer non-GET HTTP probes instead of 502 + error flood#6
Ho1yShif merged 2 commits into
mainfrom
fix/render-webui-head-probe-502

Conversation

@Ho1yShif

@Ho1yShif Ho1yShif commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Problem

On the Render deploy, the live service floods its logs with a full Python
traceback once per second:

ERROR | [websockets] opening handshake failed
...
ValueError: unsupported HTTP method; expected GET; got HEAD

Root cause: nanobot's gateway serves the WebUI through the websockets
server, and that library's handshake parser only accepts GET. Something
(a hosted load balancer / uptime probe) sends HEAD / ~1×/second. The parser
raises before nanobot's process_request runs, so conn_handler logs the
failure at ERROR with a traceback and aborts the TCP connection without a
response — the prober receives a 502.

Verified against the live service: GET / → 200 (WebUI works), HEAD / → 502.

Fix

Add a ServerConnection subclass that sniffs the first request line before
the handshake is parsed:

  • GET → handed to websockets unchanged (WS upgrades + every plain-HTTP WebUI route)
  • HEAD → empty 200 (so platform health checks stay green)
  • any other method405 Allow: GET

Answered probes are closed quietly, so nothing is logged at ERROR and the
client never sees a 502. Wired via create_connection on serve() /
unix_serve().

Tests

  • New tests/channels/test_websocket_head_probe.py: HEAD → 200, GET route → 200, POST → 405, and no "opening handshake failed" ERROR logged.
  • Full websocket suite (237 tests) passes — no regression to WS upgrades, HTTP routes, demo mode, or protocol boundaries.

🤖 Generated with Claude Code

Ho1yShif and others added 2 commits July 7, 2026 21:09
nanobot's gateway serves the WebUI through the websockets server, whose
handshake parser only accepts GET. A HEAD probe (as a hosted load balancer
or uptime monitor sends) made websockets abort the connection — the client
got a 502 and a full traceback was logged at ERROR. On Render, something
probes HEAD / roughly once per second, so the logs became a continuous wall
of "opening handshake failed" tracebacks.

Add a ServerConnection subclass that sniffs the first request line before the
handshake is parsed: GET is handed to websockets unchanged (WS upgrades and
every plain-HTTP WebUI route), HEAD gets an empty 200 so health checks stay
green, and any other method gets 405. Answered probes are closed quietly, so
nothing is logged at ERROR and the client never sees a 502. Wired via
create_connection on serve()/unix_serve().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e constant

Use stdlib %s lazy formatting for the debug log (self.logger here is the
stdlib "websockets.server" logger, not nanobot's loguru logger), and reuse the
existing OPENING_HANDSHAKE_FAILED_MESSAGE constant in the test instead of
hardcoding the literal. No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Ho1yShif Ho1yShif merged commit a0f1ab1 into main Jul 8, 2026
6 checks passed
@Ho1yShif Ho1yShif deleted the fix/render-webui-head-probe-502 branch July 8, 2026 04:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant