{"record":{"id":"4cfaecea348cbf4b","repo":"chenhg5/cc-connect","slug":"weixin-missing-context-token-for-peer-q-user-m","errorCode":null,"errorMessage":"weixin: missing context_token for peer %q - user must send a message to the bot first","messagePattern":"weixin: missing context_token for peer %q - user must send a message to the bot first","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/weixin/weixin.go","lineNumber":820,"sourceCode":"}\n\nfunc (p *Platform) sendChunks(ctx context.Context, replyCtx any, content string, path sendPath) error {\n\trc, ok := replyCtx.(*replyContext)\n\tif !ok || rc == nil {\n\t\treturn fmt.Errorf(\"weixin: invalid reply context\")\n\t}\n\tif err := p.checkSendQuota(ctx, path); err != nil {\n\t\treturn err\n\t}\n\tif strings.TrimSpace(rc.contextToken) == \"\" {\n\t\trc.contextToken = p.getContextToken(rc.peerUserID)\n\t}\n\tif strings.TrimSpace(rc.contextToken) == \"\" {\n\t\tslog.Error(\"weixin: cannot send message - missing context_token\",\n\t\t\t\"peer\", rc.peerUserID,\n\t\t\t\"content_preview\", truncatePreview(content, 100),\n\t\t\t\"hint\", \"user needs to send a message to the bot first so a context_token can be captured\")\n\t\treturn fmt.Errorf(\"weixin: missing context_token for peer %q - user must send a message to the bot first\", rc.peerUserID)\n\t}\n\tif strings.TrimSpace(content) == \"\" {\n\t\treturn nil\n\t}\n\tchunks := splitUTF8(content, maxWeixinChunk)\n\ttotal := len(chunks)\n\tfor i, chunk := range chunks {\n\t\t// Add delay between chunks to avoid rate limiting (except for first chunk)\n\t\tif i > 0 {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\tcase <-time.After(weixinChunkSendDelay):\n\t\t\t}\n\t\t}\n\t\terr := p.sendChunk(ctx, rc, chunk)\n\t\tif err != nil {\n\t\t\tslog.Error(\"weixin: chunk send failed, message incomplete\",","sourceCodeStart":802,"sourceCodeEnd":838,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/weixin/weixin.go#L802-L838","documentation":"WeChat's ilink sendmessage API requires a context_token captured from the user's most recent inbound message. If the reply context has no context_token and none is cached for the peer user, sendChunks refuses to send and returns this error, since any send attempt would be rejected by the server.","triggerScenarios":"The bot attempts a proactive push (Send, cron, timer) to a peer who has never messaged the bot, or whose captured context_token is missing/expired from the token cache and sync buffer.","commonSituations":"Bot restarted with an empty state_dir losing cached tokens; user's context_token expired after inactivity; first-ever message to a new user attempted as a push instead of waiting for an inbound message.","solutions":["Ask the user to send any message to the bot first, then reply within the token validity window","Persist state_dir so context tokens survive restarts","Convert proactive pushes into replies triggered by user activity","Reduce push volume so tokens don't expire between sends"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"if strings.TrimSpace(rc.ContextToken) == \"\" {\n    // cannot push; queue message until the user messages the bot\n    queueForLaterReply(peerUserID, content)\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := p.Send(ctx, rc, msg); err != nil && strings.Contains(err.Error(), \"missing context_token\") {\n    log.Warn(\"user must message the bot first; queuing\", \"peer\", rc.PeerUserID)\n    queueForLaterReply(rc.PeerUserID, msg)\n}","preventionTips":["Never push to users who haven't messaged the bot","Persist state_dir so captured tokens survive restarts","Reply promptly while the user's token is fresh","Treat pushes to silent peers as best-effort with fallback queuing"],"tags":["go","weixin","state","context-token"],"backgroundTag":"missing-required-state","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}