{"record":{"id":"1070349c8758d15b","repo":"chenhg5/cc-connect","slug":"dingtalk-sendfile-invalid-reply-context-type-t","errorCode":null,"errorMessage":"dingtalk: SendFile: invalid reply context type %T","messagePattern":"dingtalk: SendFile: invalid reply context type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/dingtalk/dingtalk.go","lineNumber":1103,"sourceCode":"\tif p.cardTemplateID == \"\" {\n\t\treturn nil, fmt.Errorf(\"dingtalk: card_template_id not configured\")\n\t}\n\tif p.isCardDegraded() {\n\t\treturn nil, fmt.Errorf(\"dingtalk: card API temporarily degraded\")\n\t}\n\trc, ok := replyCtx.(replyContext)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"dingtalk: invalid reply context type %T\", replyCtx)\n\t}\n\treturn p.createAICard(ctx, rc)\n}\n\n// SendFile uploads and sends a file via DingTalk oToMessages API.\n// Implements core.FileSender.\nfunc (p *Platform) SendFile(ctx context.Context, rctx any, file core.FileAttachment) error {\n\trc, ok := rctx.(replyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"dingtalk: SendFile: invalid reply context type %T\", rctx)\n\t}\n\n\tname := file.FileName\n\tif name == \"\" {\n\t\tname = \"file\"\n\t}\n\n\tmediaID, err := p.uploadMedia(ctx, file.Data, name, \"file\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dingtalk: upload file: %w\", err)\n\t}\n\n\tslog.Debug(\"dingtalk: file uploaded\", \"media_id\", mediaID, \"name\", name, \"size\", len(file.Data))\n\n\ttoken, err := p.getAccessToken()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dingtalk: get access token: %w\", err)\n\t}","sourceCodeStart":1085,"sourceCodeEnd":1121,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/dingtalk/dingtalk.go#L1085-L1121","documentation":"SendFile type-asserts its rctx parameter to the DingTalk platform's internal replyContext; this error means the value passed is not a DingTalk reply context (foreign platform's context, nil, or wrong concrete type). File replies must use the reply context belonging to the same platform instance.","triggerScenarios":"Calling SendFile with a reply context from another platform; passing nil; replaying a context from a different DingTalk Platform instance or stale build.","commonSituations":"Cross-platform message routing bugs; cached reply contexts reused after platform restart; engine handing a telegram context to the dingtalk platform.","solutions":["Pass only reply contexts obtained from this DingTalk platform's message handling","Check the engine routing so file sends go to the platform that produced the context","Clear persisted/cached reply contexts after restarts or upgrades","Ensure you're not wrapping the context in another type (e.g. a struct with an embedded context)"],"exampleFix":"// before\np.SendFile(ctx, genericCtx, file)\n// after\nif _, ok := genericCtx.(dingtalk.ReplyContext); !ok {\n    return fmt.Errorf(\"not a dingtalk reply context\")\n}\np.SendFile(ctx, genericCtx, file)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func canSendFile(p core.Platform, rctx any) bool {\n    fs, ok := p.(core.FileSender)\n    if !ok { return false }\n    _ = fs\n    return rctx != nil // and platform-specific context check\n}","tryCatchPattern":"if err := p.SendFile(ctx, rctx, file); err != nil {\n    if strings.Contains(err.Error(), \"invalid reply context\") {\n        return fmt.Errorf(\"file send routed to wrong platform context: %w\", err)\n    }\n    return err\n}","preventionTips":["Route file sends through the same platform instance that produced the reply context","Check for core.FileSender capability before calling SendFile","Avoid persisting and replaying reply contexts across restarts"],"tags":["dingtalk","type-mismatch","file-upload"],"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"}