{"record":{"id":"c51a4ea1ebc630f9","repo":"HKUDS/Vibe-Trading","slug":"wechat-context-token-missing-for-chat-id-msg-chat","errorCode":null,"errorMessage":"WeChat context_token missing for chat_id={msg.chat_id}, cannot send","messagePattern":"WeChat context_token missing for chat_id=(.+?), cannot send","errorType":"error_code","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"agent/src/channels/weixin.py","lineNumber":1136,"sourceCode":"        # Empty progress messages (e.g. after_iteration tool_events) must\n        # NOT act as separators — they have no visible content.\n        if is_progress and not content and not (msg.media or []):\n            self.logger.debug(\n                \"Skipped empty progress message for {} (no visible content)\",\n                msg.chat_id,\n            )\n            return\n\n        # Flush buffered hints before sending any visible message.\n        await self._flush_tool_hints(msg.chat_id)\n\n        if not is_progress:\n            await self._stop_typing(msg.chat_id, clear_remote=True)\n\n        ctx_token = self._context_tokens.get(msg.chat_id, \"\")\n        ctx_token = await self._refresh_context_token_if_stale(msg.chat_id, ctx_token)\n        if not ctx_token:\n            raise RuntimeError(\n                f\"WeChat context_token missing for chat_id={msg.chat_id}, cannot send\"\n            )\n\n        typing_ticket = \"\"\n        with suppress(Exception):\n            typing_ticket = await self._get_typing_ticket(msg.chat_id, ctx_token)\n\n        if typing_ticket:\n            with suppress(Exception):\n                await self._send_typing(msg.chat_id, typing_ticket, TYPING_STATUS_TYPING)\n\n        typing_keepalive_stop = asyncio.Event()\n        typing_keepalive_task: asyncio.Task | None = None\n        if typing_ticket:\n            typing_keepalive_task = asyncio.create_task(\n                self._typing_keepalive_loop(msg.chat_id, typing_ticket, typing_keepalive_stop)\n            )\n","sourceCodeStart":1118,"sourceCodeEnd":1154,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/channels/weixin.py#L1118-L1154","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait weixin_channel.send(OutboundMessage(chat_id=target, ...))\n\n// after\nif not weixin_channel._context_tokens.get(target):\n    await weixin_channel.send(OutboundMessage(chat_id=known_chat, text=\"Please message me first\"))\nelse:\n    await weixin_channel.send(OutboundMessage(chat_id=target, ...))","handlingStrategy":"validation","validationCode":"def has_context(ch, chat_id: str) -> bool:\n    return bool(ch._context_tokens.get(chat_id))","typeGuard":null,"tryCatchPattern":"try:\n    await channel.send(msg)\nexcept RuntimeError as e:\n    if \"context_token missing\" in str(e):\n        notify_user_to_initiate_contact(msg.chat_id)\n    else:\n        raise","preventionTips":["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."],"tags":["wechat","context-token","chat-state","precondition"],"backgroundTag":"missing-conversation-context-token","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}