HKUDS/Vibe-Trading · error · RuntimeError
WeChat context_token missing for chat_id={msg.chat_id}, cann
Error message
WeChat context_token missing for chat_id={msg.chat_id}, cannot send What it means
send() requires a per-conversation context_token for the target chat; after refreshing a stale token via _refresh_context_token_if_stale, an empty token means the channel has no valid context for that chat_id and cannot construct the sendmessage request. WeChat iLink requires this token as an anti-abuse/conversation-integrity parameter.
Source
Thrown at agent/src/channels/weixin.py:1136
# Empty progress messages (e.g. after_iteration tool_events) must
# NOT act as separators — they have no visible content.
if is_progress and not content and not (msg.media or []):
self.logger.debug(
"Skipped empty progress message for {} (no visible content)",
msg.chat_id,
)
return
# Flush buffered hints before sending any visible message.
await self._flush_tool_hints(msg.chat_id)
if not is_progress:
await self._stop_typing(msg.chat_id, clear_remote=True)
ctx_token = self._context_tokens.get(msg.chat_id, "")
ctx_token = await self._refresh_context_token_if_stale(msg.chat_id, ctx_token)
if not ctx_token:
raise RuntimeError(
f"WeChat context_token missing for chat_id={msg.chat_id}, cannot send"
)
typing_ticket = ""
with suppress(Exception):
typing_ticket = await self._get_typing_ticket(msg.chat_id, ctx_token)
if typing_ticket:
with suppress(Exception):
await self._send_typing(msg.chat_id, typing_ticket, TYPING_STATUS_TYPING)
typing_keepalive_stop = asyncio.Event()
typing_keepalive_task: asyncio.Task | None = None
if typing_ticket:
typing_keepalive_task = asyncio.create_task(
self._typing_keepalive_loop(msg.chat_id, typing_ticket, typing_keepalive_stop)
)
View on GitHub (pinned to 80ffdda44c)
Solutions
- Ensure the chat has an inbound message history before sending (require user-initiated contact first).
- Retry after a short delay if the refresh was rate-limited; log the refresh response for diagnosis.
- If restarts lose tokens, persist context_tokens and restore them on boot.
- Verify the chat_id is correct — a typo'd or stale chat_id will never have a token.
Example fix
// before
await weixin_channel.send(OutboundMessage(chat_id=target, ...))
// after
if not weixin_channel._context_tokens.get(target):
await weixin_channel.send(OutboundMessage(chat_id=known_chat, text="Please message me first"))
else:
await weixin_channel.send(OutboundMessage(chat_id=target, ...)) Defensive patterns
Strategy: validation
Validate before calling
def has_context(ch, chat_id: str) -> bool:
return bool(ch._context_tokens.get(chat_id)) Try / catch
try:
await channel.send(msg)
except RuntimeError as e:
if "context_token missing" in str(e):
notify_user_to_initiate_contact(msg.chat_id)
else:
raise Prevention
- Only reply to chats that have messaged the bot first.
- Persist context_tokens across restarts.
- Retry sends after a short delay to allow token refresh.
When it happens
Trigger: Sending to a chat_id for which no context_token was ever captured (bot has not received a message in that chat), or the stored token expired and the refresh call returned empty.
Common situations: Proactively messaging a user/chat that has never messaged the bot first (no inbound context to harvest); chat token TTL elapsed during a long pause; process restart losing in-memory _context_tokens dict; WeChat rate-limiting the token refresh endpoint.
Related errors
- WeChat client not initialized or not authenticated
- 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.
- WeChat send text error (ret={ret}, errcode={errcode}): {data
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/c51a4ea1ebc630f9.
Report an issue: GitHub.