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)