Tencent/WeKnora · error
appchat api error: code=%d msg=%s
Error message
appchat api error: code=%d msg=%s
What it means
sendToAppChat posts a reply to a WeCom appchat (group chat) via WeChat Work's appchat send API. When WeCom responds with a non-zero errcode, the adapter surfaces it as "appchat api error: code=%d msg=%s". This is an upstream WeCom API rejection, not a local bug.
Source
Thrown at internal/im/wecom/webhook_adapter.go:336
return fmt.Errorf("create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := httpClient.Do(req)
if err != nil {
return fmt.Errorf("send appchat message: %w", err)
}
defer resp.Body.Close()
var result struct {
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return fmt.Errorf("decode response: %w", err)
}
if result.ErrCode != 0 {
return fmt.Errorf("appchat api error: code=%d msg=%s", result.ErrCode, result.ErrMsg)
}
return nil
}
// sendToUser sends a message directly to a user via the application message API.
// Reference: https://developer.work.weixin.qq.com/document/path/90236
func (a *WebhookAdapter) sendToUser(ctx context.Context, accessToken, userID string, reply *im.ReplyMessage) error {
payload := map[string]interface{}{
"touser": userID,
"msgtype": "markdown",
"agentid": a.corpAgentID,
"markdown": map[string]string{
"content": reply.Content,
},
}
payloadBytes, err := json.Marshal(payload)View on GitHub (pinned to 988cbb0330)
Solutions
- Read the code/msg in the error and look it up in WeCom's API error code docs (e.g. 40014 bad token, 82003 invalid chatid).
- Verify the chatid exists and the sending app is a member of that appchat.
- Refresh the access token if the code indicates token invalid/expired, then retry.
- Confirm the app has appchat send permission in WeCom admin settings.
Example fix
// before
replyTarget = "defunct-chat-id"
// after
replyTarget = chatidVerifiedViaWeComAppchatGet("current-chat-id") Defensive patterns
Strategy: retry
Validate before calling
// pre-checks before send
if chatID == "" {
return fmt.Errorf("refusing appchat send: empty chatid")
}
if token stale { /* let getAccessToken refresh; ensure corpid/secret valid */ } Try / catch
if err := a.sendToAppChat(ctx, chatID, payload); err != nil {
var code int
if n, _ := fmt.Sscanf(err.Error(), "appchat api error: code=%d", &code); n == 1 {
switch code {
case 40014, 42001: // token invalid/expired
a.invalidateToken(); return a.sendToAppChat(ctx, chatID, payload)
default:
return fmt.Errorf("appchat send rejected by wecom (code %d): %w", code, err)
}
}
return err
} Prevention
- Validate chatid exists (appchat/get) before first send and on failures.
- Keep the app as an active member of target appchats.
- Implement token-refresh-on-40xxx with bounded retries.
- Map WeCom errcodes to actionable messages in your monitoring.
When it happens
Trigger: SendReply routing to an app chat where WeCom returns errcode != 0 — e.g. invalid chatid, bot not a member of the chat, or the appchat API not enabled for the app.
Common situations: Chat was disbanded or chatid changed; the app was removed from the group; using the appchat API with an app that lacks chat permissions; typographic error in the chatid stored on the channel.
Related errors
- wecom api error: code=%d msg=%s
- failed to generate questions: %w
- get token error: code=%d msg=%s
- ollama API returned status %d: %s
- rerank call failed: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/c5f8d253041b6bf7.
Report an issue: GitHub.