{"id":"58af288ca5cb1a36","repo":"aio-libs/aiohttp","slug":"1002","errorCode":"1002","errorMessage":"Continuation frame for non started message","messagePattern":"Continuation frame for non started message","errorType":"exception","errorClass":"WebSocketError","httpStatus":null,"severity":"error","filePath":"aiohttp/_websocket/reader_c.py","lineNumber":205,"sourceCode":"        except Exception as exc:\n            self._exc = exc\n            set_exception(self.queue, exc)\n            return EMPTY_FRAME_ERROR\n\n        return EMPTY_FRAME\n\n    def _handle_frame(\n        self,\n        fin: bool,\n        opcode: int | cython_int,  # Union intended: Cython pxd uses C int\n        payload: bytes | bytearray,\n        compressed: int | cython_int,  # Union intended: Cython pxd uses C int\n    ) -> None:\n        msg: WSMessage\n        if opcode in {OP_CODE_TEXT, OP_CODE_BINARY, OP_CODE_CONTINUATION}:\n            # Validate continuation frames before processing\n            if opcode == OP_CODE_CONTINUATION and self._opcode == OP_CODE_NOT_SET:\n                raise WebSocketError(\n                    WSCloseCode.PROTOCOL_ERROR,\n                    \"Continuation frame for non started message\",\n                )\n\n            # load text/binary\n            if not fin:\n                # got partial frame payload\n                if opcode != OP_CODE_CONTINUATION:\n                    self._opcode = opcode\n                self._partial += payload\n                return\n\n            has_partial = bool(self._partial)\n            if opcode == OP_CODE_CONTINUATION:\n                opcode = self._opcode\n                self._opcode = OP_CODE_NOT_SET\n            # previous frame was non finished\n            # we should get continuation opcode","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/_websocket/reader_c.py#L187-L223","documentation":"WebSocketError with close code 1002 (PROTOCOL_ERROR) raised in WebSocketReader._handle_frame when a CONTINUATION opcode (0x0) frame arrives but no data message was previously started (self._opcode == OP_CODE_NOT_SET). RFC 6455 requires a continuation frame to follow a non-final TEXT/BINARY frame; a continuation with no preceding start frame is malformed. This variant is from the Cython reader (reader_c.py) used when extensions are compiled.","triggerScenarios":"The remote peer sends a frame whose opcode is 0x0 (continuation) as the very first data frame, or after a previous message was already finalized. In the normal receive() loop this is surfaced as a message with msg.type == WSMsgType.ERROR and msg.data.code == 1002, and the connection is closed with code 1002.","commonSituations":"A buggy/non-RFC-6455 client or server that emits continuation frames out of order; a corrupting intermediary (misconfigured proxy/LoadBalancer) that drops or reorders the initial TEXT/BINARY frame; custom low-level frame injection that forgets the leading data frame.","solutions":["In your receive loop, check 'if msg.type is WSMsgType.ERROR' and inspect msg.data.code to detect the 1002 and close cleanly.","Verify the peer implementation starts every fragmented message with a TEXT (0x1) or BINARY (0x2) frame before sending CONTINUATION (0x0).","Check intermediaries (nginx/haproxy/envoy) for WebSocket frame corruption and test with a direct connection.","Capture the raw frames (e.g. tcpdump/Wireshark) to confirm the missing leading data frame."],"exampleFix":"# before\nmsg = await ws.receive()\nprint(msg.data)  # ignores protocol error, connection silently broken\n\n# after\nmsg = await ws.receive()\nif msg.type is aiohttp.WSMsgType.ERROR:\n    print('ws protocol error:', msg.data, msg.data.code)  # WebSocketError, 1002\n    await ws.close()","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"from aiohttp import WSMsgType, WSMessageError\n\ndef is_ws_error(msg) -> bool:\n    return msg.type is WSMsgType.ERROR","tryCatchPattern":"msg = await ws.receive()\nif msg.type is aiohttp.WSMsgType.ERROR:\n    exc = msg.data  # WebSocketError with .code == 1002\n    log.warning('continuation-without-start: %s (code %s)', exc, exc.code)\n    await ws.close()","preventionTips":["Always check msg.type is WSMsgType.ERROR in your receive loop; WebSocket protocol errors arrive as messages, not exceptions.","Inspect msg.data.code to distinguish the failure mode (here 1002).","Ensure the peer starts fragmented messages with TEXT/BINARY before any CONTINUATION."],"tags":["websocket","protocol","fragmentation","cython","close-1002"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}