{"record":{"id":"dc17f3002931a7ce","repo":"chenhg5/cc-connect","slug":"weixin-sendmessage-nil-request","errorCode":null,"errorMessage":"weixin: sendMessage: nil request","messagePattern":"weixin: sendMessage: nil request","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/weixin/client.go","lineNumber":164,"sourceCode":"\t\tif errors.Is(err, context.DeadlineExceeded) {\n\t\t\treturn &getUpdatesResp{Ret: 0, Msgs: nil, GetUpdatesBuf: buf}, nil\n\t\t}\n\t\tvar ne net.Error\n\t\tif errors.As(err, &ne) && ne.Timeout() {\n\t\t\treturn &getUpdatesResp{Ret: 0, Msgs: nil, GetUpdatesBuf: buf}, nil\n\t\t}\n\t\treturn nil, err\n\t}\n\tvar out getUpdatesResp\n\tif err := json.Unmarshal(raw, &out); err != nil {\n\t\treturn nil, fmt.Errorf(\"weixin: getUpdates json: %w\", err)\n\t}\n\treturn &out, nil\n}\n\nfunc (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 {","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/weixin/client.go#L146-L182","documentation":"sendMessage is the low-level API call that posts an outbound message to WeChat. It validates its argument first and rejects a nil *sendMessageReq to avoid a nil-pointer panic during json.Marshal. This is a programmer error passed up by callers like sendText/sendSingleItem.","triggerScenarios":"A caller (sendText, sendSingleItem) constructs no request — e.g. sendSingleItem called with an empty/zero item so the req pointer is never built, or refactored code paths pass nil directly.","commonSituations":"Code changes that build the request conditionally and skip building it on edge cases; calling sendSingleItem with no media/text item after validation gaps upstream.","solutions":["Find the caller producing nil (sendText or sendSingleItem) and ensure it always builds sendMessageReq","Add an upstream guard returning a descriptive error when there is nothing to send","If sendSingleItem can be a no-op, return nil early instead of forwarding a nil request"],"exampleFix":"// before\nif len(items) == 0 { return fmt.Errorf(\"weixin: sendText: empty item_list\") }\n// after: also guard before calling sendMessage\nif len(items) == 0 { return fmt.Errorf(\"weixin: sendText: empty item_list\") }\nmsg := buildSendMessageReq(to, items, clientID)\nif msg == nil { return fmt.Errorf(\"weixin: sendText: nil request\") }","handlingStrategy":"validation","validationCode":"if msg == nil { return errors.New(\"weixin: sendMessage called with nil request\") }","typeGuard":null,"tryCatchPattern":"if err := c.sendMessage(ctx, req); err != nil {\n\tif strings.Contains(err.Error(), \"nil request\") { slog.Error(\"weixin: programmer error: nil req built upstream\") }\n\treturn err\n}","preventionTips":["Never build requests conditionally without a fallback path","Return early (nil) in callers when there is nothing to send","Add unit tests covering empty-item edge cases"],"tags":["weixin","nil","argument-validation"],"backgroundTag":"null-argument","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"}