{"record":{"id":"23614b8efb056053","repo":"chenhg5/cc-connect","slug":"dingtalk-sendaudio-invalid-reply-context-type-t","errorCode":null,"errorMessage":"dingtalk: SendAudio: invalid reply context type %T","messagePattern":"dingtalk: SendAudio: invalid reply context type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/dingtalk/dingtalk.go","lineNumber":1180,"sourceCode":"\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"dingtalk: send file failed: status=%d, body=%s\", resp.StatusCode, string(respBody))\n\t}\n\n\tslog.Info(\"dingtalk: file message sent\", \"media_id\", mediaID, \"name\", name, \"user\", rc.senderStaffId)\n\treturn nil\n}\n\nvar _ core.FileSender = (*Platform)(nil)\n\n// SendAudio uploads audio bytes to DingTalk and sends a voice message.\n// Implements core.AudioSender interface.\n// Uses DingTalk oToMessages API with msgKey: \"sampleAudio\" (voice messages).\n// DingTalk voice messages only support ogg/amr formats (not mp3).\nfunc (p *Platform) SendAudio(ctx context.Context, rctx any, audio []byte, format string) error {\n\trc, ok := rctx.(replyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"dingtalk: SendAudio: invalid reply context type %T\", rctx)\n\t}\n\n\tslog.Debug(\"dingtalk: SendAudio called\", \"format\", format, \"size\", len(audio), \"conversation_id\", rc.conversationId)\n\n\t// Convert MP3 to OGG if needed (DingTalk voice messages only support ogg/amr)\n\tif strings.ToLower(format) == \"mp3\" {\n\t\tslog.Debug(\"dingtalk: converting MP3 to OGG format (DingTalk requirement)\")\n\t\toggAudio, err := core.ConvertMP3ToOGG(ctx, audio)\n\t\tif err != nil {\n\t\t\tslog.Warn(\"dingtalk: MP3 to OGG conversion failed\", \"error\", err)\n\t\t\t// Fallback: try AMR format instead\n\t\t\tamrAudio, err := core.ConvertMP3ToAMR(ctx, audio)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"dingtalk: convert MP3 to AMR failed: %w\", err)\n\t\t\t}\n\t\t\taudio = amrAudio\n\t\t\tformat = \"amr\"\n\t\t} else {","sourceCodeStart":1162,"sourceCodeEnd":1198,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/dingtalk/dingtalk.go#L1162-L1198","documentation":"SendAudio implements the core.AudioSender interface and expects the reply-context parameter to be the platform's internal replyContext type. If the engine passes any other value (nil, or a context from a different platform), the type assertion fails and this error is returned. It signals a wiring/programming bug, not a user input problem.","triggerScenarios":"Calling SendAudio with rctx that is not of type dingtalk.replyContext — e.g. nil, a context.Context passed by mistake, or a replyContext produced by another platform adapter.","commonSituations":"Engine misconfiguration routing a DingTalk audio send with a foreign reply context; tests passing context.TODO(); custom code calling SendAudio directly instead of via the engine.","solutions":["Ensure the value comes from DingTalk's message-handling path (the platform constructs replyContext itself)","Never pass context.Context as the reply-context argument — they are different types","Check that the message originated from the DingTalk platform before calling SendAudio"],"exampleFix":"// before\nerr := p.SendAudio(ctx, ctx, audio, \"mp3\") // wrong: ctx is context.Context\n// after\nrc := dingtalk.ReplyContextFromMessage(msg)\nerr := p.SendAudio(ctx, rc, audio, \"mp3\")","handlingStrategy":"type-guard","validationCode":"if rc, ok := rctx.(dingtalk.ReplyContext); !ok { return fmt.Errorf(\"expected dingtalk reply context, got %T\", rctx) }","typeGuard":"func validReplyContext(rctx any) (dingtalk.ReplyContext, bool) { rc, ok := rctx.(dingtalk.ReplyContext); return rc, ok }","tryCatchPattern":"if err := p.SendAudio(ctx, rctx, audio, \"mp3\"); err != nil && strings.Contains(err.Error(), \"invalid reply context type\") { log.Errorf(\"wrong reply context %T passed — use the platform-provided one\", rctx) }","preventionTips":["Always pass the reply context supplied by the platform's message handler, never context.Context","Don't call SendAudio directly with hand-built contexts; go through the engine","Add a compile-time assertion that engine wiring uses the correct adapter"],"tags":["dingtalk","type-assertion","programming-error"],"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"}