{"record":{"id":"07ddf4daaf25e64c","repo":"chenhg5/cc-connect","slug":"wecom-ws-chatid-is-empty-cannot-send-proactive-m","errorCode":null,"errorMessage":"wecom-ws: chatID is empty, cannot send proactive message","messagePattern":"wecom-ws: chatID is empty, cannot send proactive message","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/wecom/websocket.go","lineNumber":509,"sourceCode":"\t\treturn err\n\t}\n\tslog.Debug(\"wecom-ws: reply sent\", \"user\", rc.userID, \"len\", len(content))\n\treturn nil\n}\n\n// Send sends a proactive message via aibot_send_msg (markdown format).\n// Used for follow-up messages and cron-triggered messages where no req_id is available.\n// Markdown is natively supported.\nfunc (p *WSPlatform) Send(ctx context.Context, rctx any, content string) error {\n\trc, ok := rctx.(wsReplyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"wecom-ws: invalid reply context type %T\", rctx)\n\t}\n\tif content == \"\" {\n\t\treturn nil\n\t}\n\tif rc.chatID == \"\" {\n\t\treturn fmt.Errorf(\"wecom-ws: chatID is empty, cannot send proactive message\")\n\t}\n\n\tchunks := splitByBytes(content, 2000)\n\tfor i, chunk := range chunks {\n\t\treqID := p.generateReqID(\"aibot_send_msg\")\n\t\tframe := map[string]any{\n\t\t\t\"cmd\":     \"aibot_send_msg\",\n\t\t\t\"headers\": map[string]string{\"req_id\": reqID},\n\t\t\t\"body\": map[string]any{\n\t\t\t\t\"chatid\":  rc.chatID,\n\t\t\t\t\"msgtype\": \"markdown\",\n\t\t\t\t\"markdown\": map[string]string{\n\t\t\t\t\t\"content\": chunk,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tif err := p.writeAndWaitAck(ctx, frame, reqID); err != nil {\n\t\t\tslog.Error(\"wecom-ws: send failed\", \"user\", rc.userID, \"chunk\", i, \"error\", err)","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/wecom/websocket.go#L491-L527","documentation":"Guard in wecom-ws Send (proactive aibot_send_msg path): the reply context is valid but its chatID field is empty, so there is no conversation to address a follow-up/cron message to. This typically happens when the context was built from a callback payload that lacked the chat identifier, or a session key was reconstructed without a chatID segment.","triggerScenarios":"Thrown at platform/wecom/websocket.go:509 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Verify the callback handler stores chatID into wsReplyContext before invoking Send","Check that the session key used to rebuild the context contains the chatID component (wecom:{chatID}:{userID})","Skip and log the dropped message instead of retrying — the missing ID is not transient","Fall back to a user-addressed API path if the deployment supports it"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}