Shopify app dev crashes when an /extensions websocket client sends a bad frame

I have reproduced the issue on the latest CLI version.

Yes, I am on the latest version

I have searched existing posts and this report is not a duplicate.

Yes, this isn’t a duplicate

In which of these areas are you experiencing a problem?

App

Expected behavior

shopify app dev keeps running and only the bad connection closes.

The connection handler (the one that logs “Websocket connection successfully established”) gives each socket a message listener but no error listener:

r.send(JSON.stringify(o)), r.on("message", is(t, e))

Adding one next to it fixes the crash:

ws.on("error", (error) => outputDebug(`Websocket client error: ${error.message}`, stdout))

We patched our local bundle this way. The repro below then closes only that connection, and two full test runs logged 7 of these errors without a crash.

Actual behavior

The whole dev process exits when a client of the UI extensions websocket (/extensions) sends a malformed frame. The proxy port goes down with it, so the tunnel has nothing to forward to.

ws emits error on the socket when it rejects the frame. Nothing listens, so Node throws it as an uncaught exception:

RangeError: Max payload size exceeded
    at Le.haveLength (node_modules/@shopify/cli/dist/chunk-UOHNRH6E.js:1:13680)
    at Le.getPayloadLength64 (node_modules/@shopify/cli/dist/chunk-UOHNRH6E.js:1:13490)
    at Le.startLoop (node_modules/@shopify/cli/dist/chunk-UOHNRH6E.js:1:10870)
    at Le._write (node_modules/@shopify/cli/dist/chunk-UOHNRH6E.js:1:10225)

We hit this several times per run in long automated checkout tests, where checkout preview pages connect to <app url>/extensions.

Reproduction steps

Start shopify app dev for an app with a UI extension, then send one malformed frame to the proxy port. This one claims a 1 TiB payload:

// node bad-frame.mjs <proxy port>
import net from "node:net";
const s = net.connect(Number(process.argv[2]), "::1", () => {
  s.write("GET /extensions HTTP/1.1\r\nHost: localhost\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n" +
    "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n");
});
s.once("data", () => {
  s.write(Buffer.from([0x81, 0xff, 0, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4]));
  setTimeout(() => s.destroy(), 500);
});

The CLI prints the RangeError and exits.

Verbose output

Tail of shopify app dev --verbose (CLI 4.9.4) when the repro frame arrives. The connected payload is our app’s extension list, so I left it out.

2026-10-25T21:26:03.581Z: Upgrading HTTP request to a websocket connection
2026-10-25T21:26:03.581Z: Websocket connection successfully established
2026-10-25T21:26:03.581Z: Sending connected payload: { ...extension list omitted... }
RangeError: Max payload size exceeded
    at Le.haveLength (node_modules/@shopify/cli/dist/chunk-UOHNRH6E.js:1:13680)
    at Le.getPayloadLength64 (node_modules/@shopify/cli/dist/chunk-UOHNRH6E.js:1:13490)
    at Le.startLoop (node_modules/@shopify/cli/dist/chunk-UOHNRH6E.js:1:10870)
    at Le._write (node_modules/@shopify/cli/dist/chunk-UOHNRH6E.js:1:10225)
    at writeOrBuffer (node:internal/streams/writable:574:12)
    at _write (node:internal/streams/writable:503:10)
    at Writable.write (node:internal/streams/writable:512:10)
    at Socket.me (node_modules/@shopify/cli/dist/chunk-UOHNRH6E.js:1:39679)
    at Socket.emit (node:events:514:28)
    at Socket.emit (node:domain:489:12)

The process exits right after this.

Operating system

macOS 27.0.1

CLI version

4.9.4 (also 3.94.3)

Shell

zsh

Nodejs version

v24.22.1 (also v22.21.1)

What language and version are you using in your application?

Node 24 (Express + React)

Hi @btrain137, thanks for sharing the reproduction and proposed fix. I confirmed the same crash in an isolated test using the WebSocket code packaged with CLI 5.0.0, and your error handler prevented it there too.

I’ve shared your report and these results for review. I’ll update this thread when I know more.