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
- Match errcode against WeChat iLink docs in the message: rate-limit codes -> queue and slow down sends; token codes -> refresh context token.
- Coalesce/throttle outbound messages (the code already buffers tool hints — extend the pattern to all sends).
- Retry once after refreshing the context_token for transient token staleness.
- 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
- Throttle/coalesce outbound messages to stay under ~7 msgs / 5 min per user.
- Refresh context_token before retrying token-related errcodes.
- Parse errcode from the message to distinguish rate limits from content blocks.
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
- Failed to get QR code from WeChat API: {data}
- WeChat session paused, {remaining_min} min remaining (errcod
- getUpdates failed: ret={ret} errcode={errcode} errmsg={data.
- getuploadurl returned no upload URL (need upload_full_url or
- WeChat send media error (ret={ret}, errcode={errcode}): {dat
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/35b0f0dd3d79750e.
Report an issue: GitHub.