Skip to content

Unhandled 'error' event causes crash on network disconnect (ENOTFOUND) in v26.0.0 #546

@kyesil

Description

@kyesil

I am encountering a critical issue with @binance/spot version ^26.0.0. When the internet connection is lost while a user stream (WebSocket API) is running, the application crashes due to an unhandled 'error' event.

Unlike version v20.0.1, where the connection would attempt to reconnect or allow the error to be caught, the current version throws an unhandled exception effectively killing the Node.js process.

Environment

Package version: @binance/spot ^26.0.0
Node.js version: v24.11.1
OS: Windows 11

Steps to Reproduce

Initialize the Spot client.
Start a WebSocket connection (e.g., user stream).
Disconnect the internet connection (simulate network loss).
The application crashes with Error: getaddrinfo ENOTFOUND.

Actual Behavior

The application crashes immediately. The internal reconnection logic does not seem to trigger, and I am unable to catch the error in my application code because it is thrown as an unhandled event.

Expected Behavior

The library should either:

Handle the error internally and trigger the auto-reconnect logic (as observed in v20.0.1).
Or emit the error in a way that can be caught by the user without crashing the process.

Error Log

[2025-12-10T12:16:11.266Z] [info] Establishing Websocket connection with id a41db9caba555627e627b4ce2e0fb829 to: wss://ws-api.testnet.binance.vision/ws-api/v3
[2025-12-10T12:16:11.268Z] [error] Received error from server
[2025-12-10T12:16:11.271Z] [error] Error: getaddrinfo ENOTFOUND ws-api.testnet.binance.vision
    at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:122:26) {
  errno: -3008,
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'ws-api.testnet.binance.vision'
}
node:events:486
      throw er; // Unhandled 'error' event
      ^
Error: getaddrinfo ENOTFOUND ws-api.testnet.binance.vision
    at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:122:26)
Emitted 'error' event at:
    at WebsocketAPIBase.emit (...\node_modules\@binance\common\src\websocket.ts:44:27)
    at WebSocket.<anonymous> (...\node_modules\@binance\common\src\websocket.ts:546:18)
    at WebSocket.emit (node:events:520:35)
    at emitErrorAndClose (...\node_modules\ws\lib\websocket.js:1041:13)
    at ClientRequest.<anonymous> (...\node_modules\ws\lib\websocket.js:881:5)
    at ClientRequest.emit (node:events:508:28)
    at emitErrorEvent (node:_http_client:108:11)
    at TLSSocket.socketErrorListener (node:_http_client:575:5)
    at TLSSocket.emit (node:events:508:28)
    at emitErrorNT (node:internal/streams/destroy:170:8) {
  errno: -3008,
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'ws-api.testnet.binance.vision'
}

Node.js v24.11.1
error: script "dev:server" exited with code 1

Possible Cause & Location

Looking at the stack trace, the issue seems to originate in @binance/common/src/websocket.ts#550

It appears that at line #546 (inside the error handler), the error is re-emitted. However, if the reconnection logicfails or doesn't intercept this specific DNS error (ENOTFOUND), the error event propagates. Since there might be no listener attached to handle this specific emission sequence during the disconnect, Node.js throws the fatal error.

Code

private async initializeUserDataStream(): Promise<void> {
    try {
      this.userDataWs = await this.client.websocketAPI.connect();
      console.log(`[Client:${this.sessionId}] User data stream connected`);
      const { stream } = await this.userDataWs.userDataStreamSubscribeSignature();
      console.log(`[Client:${this.sessionId}] User data stream Subscribed`);
      this.startUserDataPingInterval();

      stream.on('message', (data: any) => {
        try {
          this.handleUserDataMessage(data);
        } catch (error: any) {
          console.error(`[Client:${this.sessionId}] Error parsing user data message: ${error.message}`);
        }
      });
      this.userDataWs.on('open', () => {
        this.isReconnectingUserData = false;
        console.log(`[Client:${this.sessionId}] User data stream connected`);
      });
      this.userDataWs.on('ping', (event: any) => {
        console.error(`[Client:${this.sessionId}] User data WebSocket ping`);
      });
      this.userDataWs.on('error', (error: any) => {
        console.error(`[Client:${this.sessionId}] User data WebSocket error`, error);
        if (!this.isReconnectingUserData) {
          this.reconnectUserDataStream();
        }
      });
      this.userDataWs.on('close', (e: any) => {
        console.log(`[Client:${this.sessionId}] connection closed`, e);
        if (!this.isReconnectingUserData) {
          this.reconnectUserDataStream();
        }
      });
    } catch (error: any) {
      console.error(`[Client:${this.sessionId}] Failed to initialize user data stream`, error);
      throw error;
    }
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions