fix(websockets): deliver exception errors to native ws clients #16336
+195
−10
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
BaseWsExceptionFilter used client.emit() to send exception payloads, which only works with socket.io. For native WebSocket clients (ws library), emit() is just EventEmitter.emit() and does not send data over the wire, causing exceptions to be silently swallowed.
Add sendExceptionToClient() and isNativeWebSocket() methods to BaseWsExceptionFilter to detect the client type and use client.send() for native WebSocket clients. Update WsExceptionsHandler guard to allow clients with send() through to the exception filter.
Closes #9056
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
When a
WsExceptionis thrown inside a gateway handler that uses@nestjs/platform-ws(rawwslibrary), the exception is silently swallowed — the client never receives any error. This happens becauseBaseWsExceptionFiltercallsclient.emit('exception', payload), which is a socket.io-specific method. On rawwsWebSocket clients,.emit()is inherited from Node'sEventEmitterand only dispatches events locally — it does not send anything over the wire. Additionally, the guard inWsExceptionsHandler(!client.emit) always passes forwsclients since they inherit.emitfromEventEmitter, but the subsequentclient.emit()call in the filter does nothing useful.Issue Number: #9056
What is the new behavior?
BaseWsExceptionFilternow has asendExceptionToClient()method that detects the client type and uses the appropriate transport:send+ numericreadyState+ nonsp): sendsJSON.stringify({ event, data: payload })viaclient.send(), matching the format used byWsAdapter.bindMessageHandlersfor normalresponses
client.emit(event, payload)(existing behavior, unchanged)isNativeWebSocket()helper method distinguishes raw ws clients from socket.io socketsWsExceptionsHandlerguard updated from!client.emitto!client.emit && !client.sendso raw ws clients reach the exception filtersendExceptionToClient()andisNativeWebSocket()areprotected, allowing users who extendBaseWsExceptionFilterto override them for custom adaptersDoes this PR introduce a breaking change?
Other information
Unit tests added for raw ws client error delivery, readyState guard, bare client bail-out, and
isNativeWebSocketdetection. E2e test added to verifyWsExceptionerrors are received by raw ws clients when usingWsAdapter.