{"record":{"id":"2d28fcc659f55796","repo":"chenhg5/cc-connect","slug":"qq-invalid-reply-context","errorCode":null,"errorMessage":"qq: invalid reply context","messagePattern":"qq: invalid reply context","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qq/qq.go","lineNumber":449,"sourceCode":"\t\t// raw_message fallback (string with CQ codes)\n\t\tif raw, ok := payload[\"raw_message\"].(string); ok {\n\t\t\ttextParts = append(textParts, stripCQCodes(raw))\n\t\t}\n\t}\n\n\treturn strings.TrimSpace(strings.Join(textParts, \"\")), images, files, audio\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(\"qq: invalid reply context\")\n\t}\n\n\tparams := map[string]any{\n\t\t\"message\": content,\n\t}\n\n\tif rctx.messageType == \"group\" {\n\t\tparams[\"group_id\"] = rctx.groupID\n\t\t_, err := p.callAPI(\"send_group_msg\", params)\n\t\treturn err\n\t}\n\n\tparams[\"user_id\"] = rctx.userID\n\t_, err := p.callAPI(\"send_private_msg\", params)\n\treturn err\n}\n\n// SendImage sends an image to the conversation.","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qq/qq.go#L431-L467","documentation":"Returned by Platform.Send when the replyCtx argument is not a *replyContext. The Send API accepts an opaque `any` reply context that must be the internal *replyContext type produced by this platform when it received a message; any other value (nil, a string chat ID, a context from another platform) fails the type assertion.","triggerScenarios":"Calling Send(ctx, replyCtx, content) with replyCtx that is nil, a plain string/int64 conversation ID, a *replyContext value (not pointer), or a reply context obtained from a different platform adapter.","commonSituations":"Persisting a reply context to JSON and passing the untyped result back; mixing platform adapters (using a Feishu reply context with the QQ platform); hand-crafting a reply context instead of using the one delivered with the inbound message; serialization round-trip that lost the concrete pointer type.","solutions":["Pass the replyCtx value exactly as delivered by the platform's inbound message event — do not rebuild it.","Ensure the value is *qq.replyContext (pointer, from the qq package), not a copy or an interface re-wrap.","Do not serialize reply contexts across processes; if you must persist routing info, store your own keys and re-resolve via the platform.","Verify you are calling Send on the same Platform instance that produced the reply context."],"exampleFix":"// before\nerr := platform.Send(ctx, \"123456\", \"hello\") // plain string ID\n\n// after\nerr := platform.Send(ctx, msg.ReplyCtx(), \"hello\") // ctx delivered with the inbound message","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isQQReplyContext(v any) bool {\n    _, ok := v.(*replyContext)\n    return ok\n}","tryCatchPattern":"if err := p.Send(ctx, replyCtx, content); err != nil {\n    if strings.Contains(err.Error(), \"invalid reply context\") {\n        slog.Error(\"replyCtx lost or wrong type\", \"type\", fmt.Sprintf(\"%T\", replyCtx))\n    }\n    return err\n}","preventionTips":["Always pass the replyCtx delivered with the inbound message, untouched","Never serialize reply contexts across processes or platforms","Keep one Platform instance per conversation domain","Assert the concrete type in tests before wiring Send calls"],"tags":["type-assertion","api-misuse","qq"],"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"}