chenhg5/cc-connect · error
weixin: context_token is required for send
Error message
weixin: context_token is required for send
What it means
WeChat iLink outbound sends require a context_token obtained from the conversation config; the client enforces this before building the request. sendText refuses to send when the token is empty because the API would reject the message anyway.
Source
Thrown at platform/weixin/client.go:255
func (c *apiClient) sendTyping(ctx context.Context, userID, typingTicket string, status int) error {
req := sendTypingReq{
IlinkUserID: userID,
TypingTicket: typingTicket,
Status: status,
BaseInfo: baseInfo{ChannelVersion: channelVersion},
}
payload, err := json.Marshal(req)
if err != nil {
return err
}
_, err = c.post(ctx, "ilink/bot/sendtyping", payload, 0, "sendTyping")
return err
}
func (c *apiClient) sendText(ctx context.Context, to, text, contextToken, clientID string) error {
if strings.TrimSpace(contextToken) == "" {
return fmt.Errorf("weixin: context_token is required for send")
}
items := []messageItem{}
if strings.TrimSpace(text) != "" {
items = append(items, messageItem{
Type: messageItemText,
TextItem: &textItem{Text: text},
})
}
if len(items) == 0 {
return fmt.Errorf("weixin: sendText: empty item_list")
}
msg := sendMessageReq{
Msg: weixinOutboundMsg{
FromUserID: "",
ToUserID: to,
ClientID: clientID,
MessageType: messageTypeBot,
MessageState: messageStateFinish,View on GitHub (pinned to 4000b2338a)
Solutions
- Ensure getConfig runs and its result is cached per user before any send
- Fail earlier: propagate the getConfig error instead of continuing with an empty token
- Re-fetch config on this error and retry the send once
- Verify session persistence so tokens survive restarts
Example fix
// before
if err := getConfig(...); err != nil { slog.Warn("..."); }
c.sendText(ctx, to, text, token, id) // token may be empty
// after
if err := getConfig(...); err != nil { return fmt.Errorf("weixin: get config: %w", err) }
c.sendText(ctx, to, text, token, id) Defensive patterns
Strategy: validation
Validate before calling
if strings.TrimSpace(contextToken) == "" { return errors.New("cannot send: context_token missing; fetch config first") } Type guard
func hasContextToken(t string) bool { return strings.TrimSpace(t) != "" } Try / catch
if err := sendText(ctx, to, text, token, id); err != nil {
if strings.Contains(err.Error(), "context_token is required") {
if tok, cerr := fetchContextToken(ctx, to); cerr == nil { return sendText(ctx, to, text, tok, id) }
}
return err
} Prevention
- Always cache context tokens per user after getConfig
- Never swallow getConfig errors in the send path
- Persist tokens so restarts don't lose them
- Re-fetch the token on this error and retry once
When it happens
Trigger: sendText invoked with an empty contextToken — typically when the getConfig step was skipped, failed silently, or the token expired and was cleared before this send.
Common situations: Bot restart losing cached per-user context tokens; getConfig previously failed (errors 1716/1717) and the caller proceeded anyway; first message to a user before config was ever fetched.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- weixin: sendText: empty item_list
- weixin: sendMessage: response json: %w: %s
- weixin: sendMessage: ret=%d errcode=%d errmsg=%s
- weixin: getUploadUrl: empty upload_param and upload_full_url
- weixin: missing context_token for peer %q
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/c502ec2a5b3a5c4e.
Report an issue: GitHub.