Diagnosing a wedged Chrome DevTools socket with a raw WebSocket probe

Symptom: every Chrome DevTools Protocol client command fails with context deadline exceeded, but the browser's HTTP endpoints look perfectly healthy —
curl http://localhost:9222/json/version and /json/list both respond.

That combination is ambiguous: it can't tell you whether the client tooling is
broken or the browser is. The error message is identical either way, and it's
easy to conclude "the tool is broken" when it isn't.

To disambiguate, bypass the tooling entirely and speak the protocol by hand.
Grab a target's webSocketDebuggerUrl from /json/list, then send one
command over a bare WebSocket:

import asyncio, json, websockets

async def probe(ws_url):
    async with websockets.connect(ws_url, max_size=None) as ws:
        await ws.send(json.dumps({
            "id": 1,
            "method": "Runtime.evaluate",
            "params": {"expression": "1+1"},
        }))
        print(await asyncio.wait_for(ws.recv(), timeout=5))

asyncio.run(probe("ws://127.0.0.1:9222/devtools/page/<target-id>"))

Two outcomes, two very different conclusions:

In the wedged case, don't fight it: launch a fresh Chrome on another port and
point the tooling there.

chrome --headless=new --remote-debugging-port=9223 \
    --user-data-dir=/tmp/fresh-profile --window-size=1440,1400

A five-line probe settles in seconds what error messages alone never will.