HKUDS/Vibe-Trading · error · RuntimeError

WeChat client not initialized or not authenticated

Error message

WeChat client not initialized or not authenticated

What it means

Public send() refuses to dispatch when the channel's internal _client or _token is missing, meaning the channel was never started or authentication never completed. This is a precondition check so callers fail fast instead of sending into an uninitialized WeChat iLink client.

Source

Thrown at agent/src/channels/weixin.py:1090

            "status": status,
            "base_info": BASE_INFO,
        }
        await self._api_post("ilink/bot/sendtyping", body)

    async def _typing_keepalive_loop(self, user_id: str, typing_ticket: str, stop_event: asyncio.Event) -> None:
        try:
            while not stop_event.is_set():
                await asyncio.sleep(TYPING_KEEPALIVE_INTERVAL_S)
                if stop_event.is_set():
                    break
                with suppress(Exception):
                    await self._send_typing(user_id, typing_ticket, TYPING_STATUS_TYPING)
        finally:
            pass

    async def send(self, msg: OutboundMessage) -> None:
        if not self._client or not self._token:
            raise RuntimeError("WeChat client not initialized or not authenticated")
        self._assert_session_active()

        is_progress = bool((msg.metadata or {}).get("_progress", False))

        # Buffer tool hints to coalesce consecutive ones and avoid burning
        # WeChat iLink rate-limit quota (~7 msgs / 5 min).
        if is_progress and (msg.metadata or {}).get("_tool_hint"):
            if not self.send_tool_hints:
                return
            self._pending_tool_hints.setdefault(msg.chat_id, []).append(msg.content)
            self.logger.debug(
                "Buffered tool hint for {} (count={})",
                msg.chat_id,
                len(self._pending_tool_hints[msg.chat_id]),
            )
            return

        # Reasoning deltas are invisible in WeChat (there is no reasoning

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Ensure start() (and successful QR login) completes before any send(); await a readiness signal/event.
  2. Check login status/logs first — if QR was never scanned or login failed, complete authentication.
  3. If the channel was shut down, restart and re-authenticate before sending.
  4. Add a guard in caller code to queue messages until the channel reports ready.

Example fix

// before
await weixin_channel.send(msg)

// after
await weixin_channel.wait_until_ready()  # or check a ready flag
await weixin_channel.send(msg)
Defensive patterns

Strategy: validation

Validate before calling

def channel_ready(ch) -> bool:
    return bool(getattr(ch, "_client", None) and getattr(ch, "_token", None))

if channel_ready(channel):
    await channel.send(msg)

Type guard

def is_ready(ch: "WeixinChannel") -> bool:
    return ch._client is not None and bool(ch._token)

Try / catch

try:
    await channel.send(msg)
except RuntimeError as e:
    if "not initialized or not authenticated" in str(e):
        queue_for_later(msg)  # resend after login completes
    else:
        raise

Prevention

When it happens

Trigger: Calling send(msg) on a WeixinChannel before start() completed the QR login, or after the client/token were cleared (failed login, shutdown).

Common situations: Sending a welcome/broadcast message at application startup before the channel finished QR login; integrating the channel into a framework that fires outbound hooks during initialization; login failed silently earlier and the error surfaces only at first send.

Understand the failure class

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/1742fdabea60f5ab. Report an issue: GitHub.