{"record":{"id":"13ba0fdbde22040e","repo":"chenhg5/cc-connect","slug":"bridge-invalid-reply-context-type-t","errorCode":null,"errorMessage":"bridge: invalid reply context type %T","messagePattern":"bridge: invalid reply context type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/bridge.go","lineNumber":333,"sourceCode":"\t_ ImageSender               = (*BridgePlatform)(nil)\n\t_ FileSender                = (*BridgePlatform)(nil)\n\t_ CardNavigable             = (*BridgePlatform)(nil)\n\t_ ReplyContextReconstructor = (*BridgePlatform)(nil)\n)\n\nfunc (bp *BridgePlatform) Name() string { return \"bridge\" }\n\nfunc (bp *BridgePlatform) Start(handler MessageHandler) error {\n\tbp.handler = handler\n\treturn nil\n}\n\nfunc (bp *BridgePlatform) Stop() error { return nil }\n\nfunc (bp *BridgePlatform) Reply(ctx context.Context, replyCtx any, content string) error {\n\trc, ok := replyCtx.(*bridgeReplyCtx)\n\tif !ok {\n\t\treturn fmt.Errorf(\"bridge: invalid reply context type %T\", replyCtx)\n\t}\n\treturn bp.server.sendToAdapter(rc.Platform, map[string]any{\n\t\t\"type\":        \"reply\",\n\t\t\"session_key\": rc.SessionKey,\n\t\t\"reply_ctx\":   rc.ReplyCtx,\n\t\t\"content\":     content,\n\t\t\"format\":      \"text\",\n\t})\n}\n\nfunc (bp *BridgePlatform) Send(ctx context.Context, replyCtx any, content string) error {\n\treturn bp.Reply(ctx, replyCtx, content)\n}\n\nfunc (bp *BridgePlatform) ReconstructReplyCtx(sessionKey string) (any, error) {\n\tplatform := bp.server.platformFromSessionKey(sessionKey)\n\tif platform == \"\" {\n\t\treturn nil, fmt.Errorf(\"bridge: cannot determine adapter from session key %q\", sessionKey)","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/bridge.go#L315-L351","documentation":"BridgePlatform.Reply asserts that the opaque replyCtx passed in is the internal *bridgeReplyCtx type. When a caller supplies a reply context that did not originate from this bridge (wrong platform adapter, hand-crafted value, or value from a different engine instance), the assertion fails and this error is returned. It protects the bridge from sending to a session key/adapter that does not exist.","triggerScenarios":"Calling BridgePlatform.Reply(ctx, replyCtx, content) with a replyCtx that is not a *bridgeReplyCtx — e.g. a replyCtx captured from another Platform implementation, a deserialized/stored plain string, or a manually constructed value.","commonSituations":"Persisting reply contexts across process restarts without using ReconstructReplyCtx; mixing platforms in a multi-platform setup (replying on the bridge with a context obtained from the direct feishu/telegram platform); upgrading versions where the internal reply-context type changed.","solutions":["Always obtain replyCtx from the same Platform instance's send/reply path (or from ReconstructReplyCtx on the same BridgePlatform); never reuse contexts across platforms.","If the context was persisted, call ReconstructReplyCtx(sessionKey) to regenerate a valid context instead of unmarshalling the old one yourself.","Log the %T of the value you are passing and confirm it matches the platform adapter that produced the outgoing message."],"exampleFix":"// before\nerr := bridgePlatform.Reply(ctx, oldPersistedCtx, \"hello\") // oldPersistedCtx is a raw string\n\n// after\nctxAny, err := bridgePlatform.ReconstructReplyCtx(sessionKey)\nif err != nil { return err }\nerr = bridgePlatform.Reply(ctx, ctxAny, \"hello\")","handlingStrategy":"type-guard","validationCode":"if _, ok := replyCtx.(*bridgeReplyCtx); !ok {\n    return fmt.Errorf(\"replyCtx must come from this bridge platform, got %T\", replyCtx)\n}","typeGuard":"func isBridgeReplyCtx(v any) bool { _, ok := v.(*bridgeReplyCtx); return ok }","tryCatchPattern":"if err := bp.Reply(ctx, replyCtx, content); err != nil {\n    if strings.Contains(err.Error(), \"invalid reply context type\") {\n        // regenerate via ReconstructReplyCtx and retry once\n    }\n    return err\n}","preventionTips":["Keep reply contexts opaque and bound to the Platform instance that produced them.","Never persist raw reply contexts; store session keys and call ReconstructReplyCtx instead.","Log %T of contexts in debugging helpers to catch cross-platform leakage early."],"tags":["go","type-assertion","reply-context"],"backgroundTag":"type-mismatch","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"}