{"record":{"id":"84cc7260038b3cc4","repo":"chenhg5/cc-connect","slug":"qqbot-invalid-reply-context","errorCode":null,"errorMessage":"qqbot: invalid reply context","messagePattern":"qqbot: invalid reply context","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qqbot/qqbot.go","lineNumber":221,"sourceCode":"\tif err := p.connectGateway(ctx); err != nil {\n\t\tcancel()\n\t\treturn fmt.Errorf(\"qqbot: failed to connect gateway: %w\", err)\n\t}\n\n\tslog.Info(\"qqbot: connected to QQ Bot gateway\", \"sandbox\", p.sandbox)\n\treturn nil\n}\n\n// Reply sends a message as a reply to an incoming message.\nfunc (p *Platform) Reply(ctx context.Context, replyCtx any, content string) error {\n\treturn p.Send(ctx, replyCtx, content)\n}\n\n// Send sends a message to the conversation identified by replyCtx.\nfunc (p *Platform) Send(ctx context.Context, replyCtx any, content string) error {\n\trctx, ok := replyCtx.(*replyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"qqbot: invalid reply context\")\n\t}\n\n\tchunks := core.SplitMessageCodeFenceAware(content, messageMaxLen)\n\tfor _, chunk := range chunks {\n\t\tif err := p.sendMessage(rctx, chunk); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// SendImage uploads and sends an image via QQ Bot rich media API.\n// Implements core.ImageSender.\nfunc (p *Platform) SendImage(ctx context.Context, replyCtx any, img core.ImageAttachment) error {\n\trctx, ok := replyCtx.(*replyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"qqbot: SendImage: invalid reply context type %T\", replyCtx)\n\t}","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qqbot/qqbot.go#L203-L239","documentation":"Send() requires replyCtx to be the platform's internal *replyContext type produced when the platform originally received a message. The type assertion rctx, ok := replyCtx.(*replyContext) fails for any other value, and Send returns this error instead of panicking. It means the caller passed a reply context this platform did not issue.","triggerScenarios":"Calling Send() with nil, a string chat ID, a *replyContext from a different platform package, or a replyCtx that was copied/converted into another type before being passed back.","commonSituations":"Routing a message through the wrong platform adapter (reply context captured from Telegram, sent via qqbot); storing reply contexts as interface{} and reconstructing them incorrectly; middleware serializing/deserializing the context and losing the pointer type.","solutions":["Pass the replyCtx value exactly as delivered by the platform's incoming-message event — do not rebuild or transform it.","Ensure the message is dispatched to the same platform instance that produced the reply context.","If contexts cross system boundaries, keep the original pointer in a registry keyed by conversation ID rather than re-creating it.","Add a type assertion check in the caller before invoking Send to fail fast with better diagnostics."],"exampleFix":"// before\nerr := qqPlatform.Send(ctx, conversationID, text) // conversationID is a string\n// after\nvar replyCtx any = originalEvent.ReplyContext() // keep platform-issued context\nerr := qqPlatform.Send(ctx, replyCtx, text)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func validReplyCtx(replyCtx any) bool {\n    _, ok := replyCtx.(*replyContext)\n    return ok\n}","tryCatchPattern":"if err := p.Send(ctx, replyCtx, text); err != nil {\n    if strings.Contains(err.Error(), \"invalid reply context\") {\n        // replyCtx did not come from this platform; re-route or drop\n    }\n}","preventionTips":["Always pass replyCtx verbatim from the platform's message event — never rebuild or convert it.","Keep a single engine routing layer so reply contexts cannot cross platform adapters.","Never serialize reply contexts across process boundaries and feed them back as pointers.","Type-assert in your dispatch layer to catch mismatches before calling Send."],"tags":["qqbot","type-mismatch","api-misuse"],"backgroundTag":"type-mismatch","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"}