iflytek/astron-agent · error · WebSocketClientException

WebSocketClientRecvLoopError

WebSocketClientRecvLoopError

Error message

{e}

What it means

WebSocketClientRecvLoopError wraps any unexpected exception raised while iterating received messages in recv(). WebSocketClientException instances are re-raised unchanged; everything else (JSON decode errors, connection drops, KeyError) is wrapped with the original message in extra_message.

Solutions

  1. Read extra_message to identify the underlying exception; fix that root cause first.
  2. Wrap the recv loop in reconnect logic that recreates the client on WebSocketClientException.
  3. Check server logs for abrupt disconnections or protocol errors.
  4. Keep processing logic outside the recv iteration or handle its exceptions separately so they are not masked.

Example fix

// before
async for msg in client.recv():
    handle(msg)

// after
try:
    async for msg in client.recv():
        handle(msg)
except WebSocketClientException as e:
    logger.warning(f"recv loop ended: {e}")
    await reconnect(client)
Defensive patterns

Strategy: try-catch

Try / catch

try:
    async for msg in client.recv():
        process(msg)
except WebSocketClientException as e:
    logger.warning(f"recv loop terminated: {e}")
    await reconnect(client)

Prevention

When it happens

Trigger: Iterating async for msg in client.recv() when the connection drops mid-stream, a received frame is not valid JSON downstream, or any callback/processing in the loop throws.

Common situations: Server closes the socket during a long-running stream, network interruption, malformed frames from the server, consumer code inside the async-for body raising and being misattributed to the recv loop.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/71baa759b5ae4ab2. Report an issue: GitHub.

Appendix: source

Thrown at core/plugin/aitools/common/clients/websockets_client.py:140

                    CodeEnums.WebSocketClientDataFormatError,
                    extra_message="WebSocket 数据格式错误",
                )

    async def recv(self) -> AsyncIterator[Any]:
        """Receive data from WebSocket server"""
        while self._running:
            try:
                msg = await self.recv_queue.get()
                if msg is None:
                    break
                if isinstance(msg, BaseException):
                    raise msg
                self.recv_data_list.append(msg)
                yield msg
            except WebSocketClientException:
                raise
            except Exception as e:
                raise WebSocketClientException.from_error_code(
                    CodeEnums.WebSocketClientRecvLoopError, extra_message=str(e)
                )

    async def _send_loop(self) -> None:
        """Send loop"""
        try:
            while self._running:
                data = await self.send_queue.get()
                if data == "EOF":
                    break
                await self.ws.send(data)
                await asyncio.sleep(self.send_interval)
        except websockets.exceptions.ConnectionClosedOK as e:
            log.info(f"WebSocket closed normally: {e}")
        except websockets.exceptions.ConnectionClosedError as e:
            await self.recv_queue.put(
                WebSocketClientException.from_error_code(
                    CodeEnums.WebSocketClientNotConnectedError, extra_message=str(e)

View on GitHub (pinned to 5e758547a8)