Cannot proxy websocket message of unsupported type: 257

Hello,

I have been getting error messages from the WebSocket API for a few days now.
This is found in the log file:

Jun 18 10:04:02 XXXXXXXXXXXXXXXXXXXXXXXX hassio_supervisor[604]: 2024-06-18 12:04:02.682 INFO (MainThread) [supervisor.api.proxy] Home Assistant WebSocket API error: Cannot proxy websocket message of unsupported type: 257

Jun 18 10:04:02 XXXXXXXXXXXXXXXXXXXXXXXX hassio_supervisor[604]: 2024-06-18 12:04:02.683 INFO (MainThread) [supervisor.api.proxy] Home Assistant WebSocket API for a0d7b954_nodered closed

Jun 18 10:04:02 XXXXXXXXXXXXXXXXXXXXXXXX addon_a0d7b954_nodered[604]: 18 Jun 12:04:02 - [info] [server:Home Assistant] Connection closed to http://supervisor/core

Jun 18 10:04:02 XXXXXXXXXXXXXXXXXXXXXXXX addon_a0d7b954_nodered[604]: 18 Jun 12:04:02 - [info] [server:Home Assistant] Connecting to http://supervisor/core

Jun 18 10:04:02 XXXXXXXXXXXXXXXXXXXXXXXX hassio_supervisor[604]: 2024-06-18 12:04:02.764 INFO (MainThread) [supervisor.api.proxy] Home Assistant WebSocket API error: Cannot proxy websocket message of unsupported type: 257

Jun 18 10:04:02 XXXXXXXXXXXXXXXXXXXXXXXX hassio_supervisor[604]: 2024-06-18 12:04:02.766 INFO (MainThread) [supervisor.api.proxy] Home Assistant WebSocket API for a0d7b954_vscode closed

It’s not only related to Node-Red. But also to VSCode Add-On.

Maybe could someone explain me what’s the cause for the WebSocket error message?
And what I could I do to prevent them?

1 Like

Maybe someone could help with this message?
What’s the cause of the unsupported type?

Is it something locally to my HA OS Installation? Or related to some network problem?

After the message occurred, the compete websocket API is reinitialized!

The only reason I am going to have a go at trying to contribute to this discussion is that it forces me to learn stuff. Apparently it is good to learn new stuff…

Log error messages usually tell you useful stuff, and I can see that

  • this is a message from the hassio_supervisor
  • the ‘error’ is for information only (not critical)
  • it is about the supervisor.api.proxy
    • trying to process an API call from Home Assistant WebSocket
    • getting a WebSocket message that is of an unsupported type

First up, this is not critical. It happens, the WebSocket connection from Node-RED (WebSocket nodes) back to Home Assistant has closed, due to ‘something’. After the supervisor closes the connection, it re-opens it and we carry on.

I am going to have a stab at this, and hopefully someone else who understands this stuff will correct me here, but:

Home Assistant exposes services to the world via a public API. This you get at using the normal UI front end address.

When HA is being run in fully supervised mode, what is going on is that the HA supervisor runs on the machine in a docker-container. The supervisor manages the docker-containers, and runs up another one for Home Assistant. Then, if you have the Node-RED as an addon, the supervisor runs up yet another docker-container for Node-RED.

Now, docker containers can’t talk to each other. They exist as ‘virtual’ devices, unlike physical devices on a network. The Home Assistant running in one container is desperate to share services over an API, but has to use a proxy to manage this between different docker-containers. The supervisor, which has control of all the containers including its own, sets up and runs a proxy that bridges API calls from one container to another.

The Proxy can manage WebSocket connections, and thus Node-RED (WebSocket nodes server) connects a WebSocket to the supervisor proxy and through this to HA and the special internal API point that HA provides for proxy connections from the HA container to other addon (containers).

The Proxy is written into the supervisor code. This being all ‘open source’ you can find and read the code for yourself!

https://github.com/home-assistant/supervisor/blob/13783f0d4a58146c510f05b651ee4830e3f26c31/supervisor/api/proxy.py#L175C5-L196C1

    async def _proxy_message(
        self,
        read_task: asyncio.Task,
        target: web.WebSocketResponse | ClientWebSocketResponse,
    ) -> None:
        """Proxy a message from client to server or vice versa."""
        if read_task.exception():
            raise read_task.exception()

        msg: WSMessage = read_task.result()
        if msg.type == WSMsgType.TEXT:
            return await target.send_str(msg.data)
        if msg.type == WSMsgType.BINARY:
            return await target.send_bytes(msg.data)
        if msg.type == WSMsgType.CLOSE:
            _LOGGER.debug("Received close message from WebSocket.")
            return await target.close()

        raise TypeError(
            f"Cannot proxy websocket message of unsupported type: {msg.type}"
        )

Proxy a message from client to server, or vice versa (ie from the NR WebSocket node server to the proxy, and from the proxy to HA WebSocket API, and then back from HA WebSocket API to the proxy, and from the proxy to the NR WebSocket node server).

So, as far as HA supervisor Proxy code is concerned, WebSocket message type can be text, binary, or close. Everything else throws an error - which is the one you are seeing.
Note. Close has just been added to the code in a recent PR to reduce the number of messages being seen when the client/server to the Proxy sends a ‘close connection’ message.

So, looking at another reference I found

https://docs.aiohttp.org/en/stable/websocket_utilities.html#aiohttp.WSMsgType

we get to see the WebSocket close messages, and also the WSMsgType

  • CONTINUATION (user will never get the message with this type)
  • TEXT
  • BINARY
  • PING
  • PONG
  • CLOSE
  • CLOSE FRAME
  • ERROR

Since the HA supervisor code deals with TEXT and BINARY, and now CLOSE, we have to assume that the unsupported type is one of
PING, PONG, CLOSE FRAME, ERROR

After a lot of digging I found the code for aiohttp websocket, including the IntEnum list.

https://docs.aiohttp.org/en/stable/_modules/aiohttp/http_websocket.html

class WSMsgType(IntEnum):
    # websocket spec types
    CONTINUATION = 0x0
    TEXT = 0x1
    BINARY = 0x2
    PING = 0x9
    PONG = 0xA
    CLOSE = 0x8

    # aiohttp specific types
    CLOSING = 0x100
    CLOSED = 0x101
    ERROR = 0x102

    text = TEXT
    binary = BINARY
    ping = PING
    pong = PONG
    close = CLOSE
    closing = CLOSING
    closed = CLOSED
    error = ERROR

And there it is! Type 257 is “CLOSED”.

So the ‘error’ message in the logs is actually the proxy saying that the WebSocket is closed.

You have a server that is attempting to use the WebSocket, but it has closed. The attempted call probably re-opens the WebSocket, but in the mean time the HA Supervisor Proxy gets a message of type CLOSED and, not knowing what to do with it, throws an error.

Conclusion:
You have more than one Addon using the Proxy - Node-RED and VSCode. Since both open WebSocket connections with the proxy, perhaps one (VSCode) is closing the connection (timeout?) or erroring the proxy (forced close) and then in the mean time the Node-RED WebSocket nodes server is also using the Proxy, makes a legitimate call (or receives back a return from HA) and the WebSocket is CLOSED so the Proxy gets that message, which it cannot process.

I hope this has been useful to you.
I certainly learnt a great deal today.
Corrections and contributions anyone?

1 Like

Hi. Thanks a lot for this very detailed explanation. Learned a lot from.
So now I have some points to take a look at to narrow down the reason, why the websockt is closing or closed.

Make sure you only have one WebSocket ha server config node. Importing code can bring in unwanted configuration nodes, so check and remove any excess. Too many and they conflict.

Turn on the ‘Enable heartbeat’ option, which will keep the connection alive.

As usual, make sure the websocket nodes are up to date, and the Node Red companion integration in HA. The NR addon has recently updated, and is now using Node-RED v4, so HA, addon, WebSocket and Companion must all match up.