aio-libs/aiohttp · error · WebSocketError
1007
1007
Error message
Invalid UTF-8 text message
What it means
Raised when a final TEXT frame's payload cannot be decoded as UTF-8. RFC 6455 section 8.1 requires TEXT frames to be valid UTF-8; failure is a protocol error closed with code 1007 (INVALID_TEXT). aiohttp decodes eagerly (unless decode_text=False) in _handle_frame at reader_py.py:272.
Source
Thrown at aiohttp/_websocket/reader_py.py:272
),
)
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 c0ef574e29)
Solutions
- Have the peer send binary data as a BINARY (opcode 0x2) frame instead of TEXT.
- Ensure the peer serializes text with UTF-8 specifically.
- If you intentionally want raw bytes for TEXT frames, open the WebSocket with decode_text=False and do your own validation.
Example fix
# before ws = await session.ws_connect(url) # decodes TEXT as utf-8 # after (opt into raw bytes, validate yourself) ws = await session.ws_connect(url, decode_text=False)
Defensive patterns
Strategy: validation
Validate before calling
ws = await session.ws_connect(url, decode_text=False) # get raw bytes; validate yourself
raw = msg.data
try:
text = raw.decode('utf-8')
except UnicodeDecodeError:
... Try / catch
msg = await ws.receive()
if msg.type == aiohttp.WSMsgType.ERROR and ws.exception().code == 1007:
await ws.close() Prevention
- Send binary payloads as BINARY (opcode 0x2), not TEXT
- Ensure peers encode text as UTF-8
When it happens
Trigger: A peer sends a TEXT (opcode 0x1) frame whose bytes contain invalid UTF-8 sequences (e.g. lone surrogates, truncated multibyte chars), and decode_text is True (the default).
Common situations: Peer encodes the message incorrectly (latin-1/cp1252 sent as TEXT), truncation by an intermediary, binary data mislabeled as TEXT, or a fragmented message whose UTF-8 boundary was split across frames and reassembled into invalid bytes.
Related errors
- Compress wbits must between 9 and 15, zlib does not support
- data argument must be byte-ish (%r)
- Response has not been started
- Concurrent call to receive() is not allowed
- WebSocket connection is closed.
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/51d6233dfaa8735b.json.
Report an issue: GitHub.