{"record":{"id":"0a68d83d9cd8e454","repo":"chenhg5/cc-connect","slug":"wecom-ws-sendfile-invalid-reply-context-type-t","errorCode":null,"errorMessage":"wecom-ws: SendFile: invalid reply context type %T","messagePattern":"wecom-ws: SendFile: invalid reply context type %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/wecom/websocket_outbound_media.go","lineNumber":162,"sourceCode":"\t\treturn name\n\t}\n\tswitch strings.ToLower(img.MimeType) {\n\tcase \"image/jpeg\", \"image/jpg\":\n\t\treturn \"image.jpg\"\n\tcase \"image/gif\":\n\t\treturn \"image.gif\"\n\tcase \"image/webp\":\n\t\treturn \"image.webp\"\n\tdefault:\n\t\treturn \"image.png\"\n\t}\n}\n\n// SendFile uploads and sends a file through the WeCom AI Bot WebSocket API.\nfunc (p *WSPlatform) SendFile(ctx context.Context, rctx any, file core.FileAttachment) error {\n\trc, ok := rctx.(wsReplyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"wecom-ws: SendFile: invalid reply context type %T\", rctx)\n\t}\n\tif rc.chatID == \"\" {\n\t\treturn fmt.Errorf(\"wecom-ws: chatID is empty, cannot send file\")\n\t}\n\tif len(file.Data) == 0 {\n\t\treturn fmt.Errorf(\"wecom-ws: file data is empty\")\n\t}\n\n\tmediaID, err := p.uploadWSMedia(ctx, \"file\", wsFileFileName(file), file.Data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"wecom-ws: send file: %w\", err)\n\t}\n\tif err := p.sendWSMediaMessage(ctx, rc.chatID, \"file\", mediaID); err != nil {\n\t\treturn fmt.Errorf(\"wecom-ws: send file: %w\", err)\n\t}\n\treturn nil\n}\n","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/wecom/websocket_outbound_media.go#L144-L180","documentation":"SendFile expects its rctx parameter to be the platform-internal wsReplyContext type produced when the platform delivered an inbound message. Any other value (nil, a context from another platform, or a hand-built value) cannot identify the target chat and is rejected with this type-check error.","triggerScenarios":"Calling WSPlatform.SendFile with rctx that is not a wsReplyContext — e.g. passing nil, ctx.Context, or a reply context captured from a different platform adapter.","commonSituations":"Code reuses a reply context across platforms; a test harness passes a stub; context was serialized/stored and lost its concrete type; engine called SendFile with nil because no inbound message context existed.","solutions":["Always pass the wsReplyContext value that the wecom-ws platform gave you with the inbound message","Do not construct reply contexts manually; obtain them from the engine's message dispatch","Check the %T in the error message to see which concrete type you actually passed","If context must cross layers, keep it as any and pass through unmodified"],"exampleFix":"// before\np.SendFile(ctx, ctx, file) // passes context.Context\n// after\np.SendFile(ctx, replyCtx, file) // replyCtx is the wsReplyContext from the inbound message","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"rc, ok := rctx.(wsReplyContext)\nif !ok {\n\treturn fmt.Errorf(\"SendFile requires the wecom-ws reply context, got %T\", rctx)\n}","tryCatchPattern":"if err := p.SendFile(ctx, replyCtx, file); err != nil && strings.Contains(err.Error(), \"invalid reply context type\") {\n\tlog.Error(\"reply context not from wecom-ws\", \"gotType\", fmt.Sprintf(\"%T\", replyCtx))\n}","preventionTips":["Never hand-construct reply contexts; take them from the inbound message dispatch","Do not share reply contexts across platform adapters","Read the %T in the error to identify the wrong type quickly"],"tags":["type-assertion","api-misuse","wecom"],"backgroundTag":"incompatible-source-type","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"}