iflytek/astron-agent · error · WebSocketClientException

WebSocketClientNotConnectedError

WebSocketClientNotConnectedError

Error message

{e}

What it means

WebSocketClientNotConnectedError is raised by WebSocketClient.connect when the initial websockets.connect() handshake to the server fails for any reason (DNS, TLS, refused connection, invalid URL). The client wraps the raw exception and preserves its message via extra_message. No send/recv loops are started when this fires.

Solutions

  1. Verify the WebSocket URL is reachable (curl the HTTP upgrade endpoint or ping the host/port).
  2. Check self.ws_params for correct auth credentials, headers, and ssl context.
  3. Ensure the target service is running and the port is exposed (docker-compose / k8s service).
  4. Confirm network egress (proxy, firewall) allows WebSocket upgrades to the host.

Example fix

// before
client = WebSocketClient("wss://api.example.com/ws", ws_params={})
await client.connect()

// after
client = WebSocketClient("wss://api.example.com/ws", ws_params={"extra_headers": {"Authorization": f"Bearer {token}"}})
try:
    await client.connect()
except WebSocketClientException as e:
    logger.error(f"WS connect failed: {e}")
    raise
Defensive patterns

Strategy: try-catch

Validate before calling

from urllib.parse import urlparse
import socket
def can_reach_ws(url: str) -> bool:
    p = urlparse(url)
    try:
        socket.create_connection((p.hostname, p.port or (443 if p.scheme == 'wss' else 80)), timeout=5).close()
        return True
    except OSError:
        return False

Type guard

def is_ws_url(url: str) -> bool:
    return url.startswith(('ws://', 'wss://'))

Try / catch

try:
    await client.connect()
except WebSocketClientException as e:
    logger.error(f"ws connect failed: {e}")
    await schedule_reconnect(client)

Prevention

When it happens

Trigger: Calling await client.connect() (typically via start()) when the WebSocket server is down, the URL is wrong, TLS certs fail, auth query params are rejected, or the network is unreachable — any exception from websockets.connect().

Common situations: Misconfigured ws:// vs wss:// URL, service not started yet in docker-compose, wrong port or missing API key in ws_params, firewall/proxy blocking the upgrade request, expired credentials causing server to reject the handshake.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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

Appendix: source

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

                )

                if new_url is None:
                    log.error("WebSocket auth failed")
                    raise WebSocketClientException.from_error_code(
                        CodeEnums.WebSocketClientAuthError, extra_message="ASE 鉴权失败"
                    )

                self.url = new_url
        except Exception:
            raise

    async def connect(self) -> None:
        """Connect to WebSocket server"""
        try:
            self.ws = await websockets.connect(self.url, **self.ws_params)
            self._running = True
        except Exception as e:
            raise WebSocketClientException.from_error_code(
                CodeEnums.WebSocketClientNotConnectedError, extra_message=str(e)
            )

        self._tasks.append(self.task_factory.create(self._send_loop()))
        self._tasks.append(self.task_factory.create(self._recv_loop()))

    async def send(self, data: Any) -> None:
        """Send data to WebSocket server"""
        self.send_data_list.append(data)
        if not self._running:
            raise WebSocketClientException.from_error_code(
                CodeEnums.WebSocketClientNotConnectedError,
                extra_message="WebSocket 未连接",
            )
        else:
            if isinstance(data, str) or isinstance(data, bytes):
                await self.send_queue.put(data)
            elif isinstance(data, dict) or isinstance(data, list):

View on GitHub (pinned to 5e758547a8)