HKUDS/Vibe-Trading · error · RuntimeError

WeChat send text error (ret={ret}, errcode={errcode}): {data

Error message

WeChat send text error (ret={ret}, errcode={errcode}): {data.get('errmsg', '')}

What it means

_send_text posts to ilink/bot/sendmessage and treats any non-zero ret or errcode in the response as a failure, raising RuntimeError with both codes and errmsg. This is the generic outbound text-send failure covering all WeChat-side rejections (rate limit, invalid token, blocked content, server error).

Source

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

            "client_id": client_id,
            "message_type": MESSAGE_TYPE_BOT,
            "message_state": MESSAGE_STATE_FINISH,
        }
        if item_list:
            weixin_msg["item_list"] = item_list
        if context_token:
            weixin_msg["context_token"] = context_token

        body: dict[str, Any] = {
            "msg": weixin_msg,
            "base_info": BASE_INFO,
        }

        data = await self._api_post("ilink/bot/sendmessage", body)
        ret = data.get("ret", 0)
        errcode = data.get("errcode", 0)
        if (ret is not None and ret != 0) or (errcode is not None and errcode != 0):
            raise RuntimeError(
                f"WeChat send text error (ret={ret}, errcode={errcode}): {data.get('errmsg', '')}"
            )

    async def _send_media_file(
        self,
        to_user_id: str,
        media_path: str,
        context_token: str,
    ) -> None:
        """Upload a local file to WeChat CDN and send it as a media message.

        Follows the exact protocol from ``@tencent-weixin/openclaw-weixin`` v1.0.3:
        1. Generate a random 16-byte AES key (client-side).
        2. Call ``getuploadurl`` with file metadata + hex-encoded AES key.
        3. AES-128-ECB encrypt the file and POST to CDN (``{cdnBaseUrl}/upload``).
        4. Read ``x-encrypted-param`` header from CDN response as the download param.
        5. Send a ``sendmessage`` with the appropriate media item referencing the upload.
        """

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Match errcode against WeChat iLink docs in the message: rate-limit codes -> queue and slow down sends; token codes -> refresh context token.
  2. Coalesce/throttle outbound messages (the code already buffers tool hints — extend the pattern to all sends).
  3. Retry once after refreshing the context_token for transient token staleness.
  4. If content-filtered, rephrase or drop the offending content.

Example fix

// before
await self._send_text(user_id, chat_id, text, ctx_token)

// after
try:
    await self._send_text(user_id, chat_id, text, ctx_token)
except RuntimeError as e:
    if 'rate' in str(e).lower():
        await asyncio.sleep(60); await self._send_text(user_id, chat_id, text, ctx_token)
    else:
        raise
Defensive patterns

Strategy: retry

Try / catch

try:
    await channel.send(msg)
except RuntimeError as e:
    if "send text error" in str(e):
        await asyncio.sleep(60)
        await channel.send(msg)  # single retry after backoff
    else:
        raise

Prevention

When it happens

Trigger: Any _send_text call (from send or _flush_tool_hints) where the API responds with ret != 0 or errcode != 0 — e.g. context_token invalid, exceeding the ~7 msgs / 5 min iLink rate limit, content filtered, or recipient unreachable.

Common situations: Agent bursts (multiple tool-hint flushes plus replies) hitting the iLink per-user rate limit; stale context_token after session pause; sending URLs/words WeChat content policy rejects; server-side incidents returning errcode with errmsg.

Related errors


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