workerd icon indicating copy to clipboard operation
workerd copied to clipboard

🐛 Bug Report — Runtime APIs: If WebSocket client close first, will cause workerd has Uncaught (in response) Error

Open zizifn opened this issue 1 year ago • 4 comments

Step for this error,

  1. Open the WebSocket in worker
  2. Use any websocket test client
  3. Close WebSocket in the client, below error will throw.
workerd/server/server.c++:2347: error: Uncaught exception: workerd/io/io-context.c++:1261: failed: remote.jsg.Error: The script will never generate a response.
stack: 0 0 0 0 7ff71a146272 0 7ff71a146234 0 0 0
workerd/server/server.c++:2259: error: exception = kj/compat/http.c++:2061: failed: expected !inBody; previous HTTP message body incomplete; can't write more messages
stack: 7ff71a138a6f 7ff71a1d035d 7ff71a205121 7ff71a194056 7ff71a1941fb 7ff719fb2e64 7ff71a1b28ca 0 0
-------------close----------------- CloseEvent {
  wasClean: undefined,
  reason: undefined,
  code: undefined
}
An event handler returned a promise that will be ignored. Event handlers should not have a return value and should not be async functions.                                                                                        
X [ERROR] Uncaught (in response) Error: The script will never generate a response.       

I think this is bug. I even test code from this blog, same errors as long as client close websocket first... https://blog.cloudflare.com/introducing-websockets-in-workers/

But below is my sample code.

export default {
  async fetch(request: Request) {
    let address = '';
    let portWithRandomLog = '';

    const log = (info: string, event?: any) => {
      console.log(`[${address}:${portWithRandomLog}] ${info}`, event || '');
    };

    const upgradeHeader = request.headers.get('Upgrade');
    if (!upgradeHeader || upgradeHeader !== 'websocket') {
      return new Response('Expected Upgrade: websocket', { status: 426 });
    }

    const webSocketPair = new WebSocketPair();
    const [client, webSocket] = Object.values(webSocketPair);
    const earlyDataHeader = request.headers.get('sec-websocket-protocol') || '';
    webSocket.accept();
    webSocket.addEventListener('message', (event) => {
      console.log(event.data);
      webSocket.send(`server reponse after client sent ${event.data}`);
      if (event.data === 'close') {
        webSocket.close();
      }
    });
    webSocket.addEventListener('close', async (event) => {
      console.log('-------------close-----------------', event);
    });

    webSocket.addEventListener('error', () => {
      console.log('-------------error-----------------');
    });

    return new Response(null, {
      status: 101,
      webSocket: client,
    });
  },
};

zizifn avatar May 16 '23 16:05 zizifn