aio-libs/aiohttp · error · WebSocketError

1007

1007

Error message

Invalid UTF-8 text message

What it means

A TEXT (opcode 0x01) frame's assembled payload is not valid UTF-8. RFC 6455 §6.1 requires the connection to fail with code 1007 when a text payload is non-UTF-8; aiohttp catches `UnicodeDecodeError` and closes with 1007.

Solutions

  1. Fix the peer to send UTF-8-encoded text, or use BINARY frames for non-text data.
  2. Handle `WSMsgType.ERROR` and reconnect — the connection is already failed with 1007.
Defensive patterns

Strategy: type-guard

Type guard

def is_error(msg) -> bool:
    return msg.type == aiohttp.WSMsgType.ERROR

Try / catch

msg = await ws.receive()
if msg.type == aiohttp.WSMsgType.ERROR:
    exc = msg.data            # a WebSocketError
    close_code = exc.code     # 1002/1007/1009/...
    log.warning("ws protocol error %s: %s", close_code, exc)

Prevention

When it happens

Trigger: Peer sends a TEXT frame containing bytes that are not valid UTF-8 (e.g. raw Latin-1, a multibyte sequence split incorrectly across fragments after assembly, or binary mislabeled as text).

Common situations: Peer encodes strings in a non-UTF-8 encoding; a proxy corrupts/reassembles fragments; binary data accidentally sent as a TEXT frame.

Understand the failure class

Related errors


AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11). Data as JSON: /api/errors/d717194b31f376eb. Report an issue: GitHub.

Appendix: source

Thrown at aiohttp/_websocket/reader_c.py:281

                        "Compressed message has too many deflate members",
                    ) from exc
                if self._max_msg_size and len(payload_merged) > self._max_msg_size:
                    raise WebSocketError(
                        WSCloseCode.MESSAGE_TOO_BIG,
                        f"Decompressed message exceeds size limit {self._max_msg_size}",
                    )
            elif type(assembled_payload) is bytes:
                payload_merged = assembled_payload
            else:
                payload_merged = bytes(assembled_payload)

            size = len(payload_merged)
            if opcode == OP_CODE_TEXT:
                if self._decode_text:
                    try:
                        text = payload_merged.decode("utf-8")
                    except UnicodeDecodeError as exc:
                        raise WebSocketError(
                            WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message"
                        ) from exc

                    # XXX: The Text and Binary messages here can be a performance
                    # bottleneck, so we use tuple.__new__ to improve performance.
                    # This is not type safe, but many tests should fail in
                    # test_client_ws_functional.py if this is wrong.
                    msg = TUPLE_NEW(WSMessageText, (text, size, "", WS_MSG_TYPE_TEXT))
                else:
                    # Return raw bytes for TEXT messages when decode_text=False
                    msg = TUPLE_NEW(
                        WSMessageTextBytes, (payload_merged, size, "", WS_MSG_TYPE_TEXT)
                    )
            else:
                msg = TUPLE_NEW(
                    WSMessageBinary, (payload_merged, size, "", WS_MSG_TYPE_BINARY)
                )

View on GitHub (pinned to d041d4d0fd)