{"record":{"id":"5e22e6f1e82b760f","repo":"chenhg5/cc-connect","slug":"weixin-sendmessage-response-json-w-s","errorCode":null,"errorMessage":"weixin: sendMessage: response json: %w: %s","messagePattern":"weixin: sendMessage: response json: %w: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/weixin/client.go","lineNumber":180,"sourceCode":"func (c *apiClient) sendMessage(ctx context.Context, msg *sendMessageReq) error {\n\tif msg == nil {\n\t\treturn fmt.Errorf(\"weixin: sendMessage: nil request\")\n\t}\n\tmsg.BaseInfo = baseInfo{ChannelVersion: channelVersion}\n\tpayload, err := json.Marshal(msg)\n\tif err != nil {\n\t\treturn err\n\t}\n\traw, err := c.post(ctx, \"ilink/bot/sendmessage\", payload, 0, \"sendMessage\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(bytes.TrimSpace(raw)) == 0 {\n\t\treturn nil\n\t}\n\tvar resp sendMessageResp\n\tif err := json.Unmarshal(raw, &resp); err != nil {\n\t\treturn fmt.Errorf(\"weixin: sendMessage: response json: %w: %s\", err, truncateForLog(raw, 256))\n\t}\n\tif resp.Ret != 0 {\n\t\tslog.Warn(\"weixin: sendMessage declined by API\",\n\t\t\t\"ret\", resp.Ret, \"errcode\", resp.Errcode, \"errmsg\", resp.Errmsg,\n\t\t\t\"content_len\", len(payload))\n\t\treturn fmt.Errorf(\"weixin: sendMessage: ret=%d errcode=%d errmsg=%s\",\n\t\t\tresp.Ret, resp.Errcode, resp.Errmsg)\n\t}\n\treturn nil\n}\n\nfunc (c *apiClient) getUploadURL(ctx context.Context, req getUploadURLRequest) (*getUploadURLResponse, error) {\n\treq.BaseInfo = baseInfo{ChannelVersion: channelVersion}\n\tpayload, err := json.Marshal(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\traw, err := c.post(ctx, \"ilink/bot/getuploadurl\", payload, 0, \"getUploadUrl\")","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/weixin/client.go#L162-L198","documentation":"After sendMessage posts to the WeChat API it decodes the response body into sendMessageResp. This error wraps a json.Unmarshal failure and appends a 256-byte snippet of the raw body. Non-JSON replies (HTML error pages, truncated bodies) trigger it.","triggerScenarios":"The send endpoint returns a non-JSON or truncated body: gateway 502 HTML, connection cut mid-response, or an iLink API schema change that makes the body fail to decode into sendMessageResp.","commonSituations":"Corporate proxy returning HTML; WeChat API outage or protocol change; payload so large the response is truncated; running an old client against a new API.","solutions":["Inspect the appended raw snippet (%s) to identify what came back","Retry the send; transient gateway bodies resolve on retry","Check WeChat iLink API changelog and update sendMessageResp if fields changed","Bypass/inspect proxies that inject HTML into responses"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if len(bytes.TrimSpace(raw)) == 0 { return nil } // already handled; check snippet in error for HTML","typeGuard":"func looksLikeHTML(b []byte) bool { return bytes.Contains(bytes.ToLower(b[:min(64, len(b))]), []byte(\"<html\")) }","tryCatchPattern":"if err := c.sendMessage(ctx, msg); err != nil {\n\tif strings.Contains(err.Error(), \"response json\") {\n\t\tslog.Warn(\"weixin: non-JSON send response; will retry\", \"err\", err)\n\t\ttime.Sleep(backoff)\n\t\treturn retrySend()\n\t}\n\treturn err\n}","preventionTips":["Retry transient non-JSON responses with backoff","Monitor the raw snippet for gateway/HTML patterns","Keep sendMessageResp in sync with API changelog"],"tags":["weixin","json","unmarshal","send"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}