chenhg5/cc-connect · error

bridge: invalid reply context type %T

Error message

bridge: invalid reply context type %T

What it means

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.

Source

Thrown at core/bridge.go:333

	_ ImageSender               = (*BridgePlatform)(nil)
	_ FileSender                = (*BridgePlatform)(nil)
	_ CardNavigable             = (*BridgePlatform)(nil)
	_ ReplyContextReconstructor = (*BridgePlatform)(nil)
)

func (bp *BridgePlatform) Name() string { return "bridge" }

func (bp *BridgePlatform) Start(handler MessageHandler) error {
	bp.handler = handler
	return nil
}

func (bp *BridgePlatform) Stop() error { return nil }

func (bp *BridgePlatform) Reply(ctx context.Context, replyCtx any, content string) error {
	rc, ok := replyCtx.(*bridgeReplyCtx)
	if !ok {
		return fmt.Errorf("bridge: invalid reply context type %T", replyCtx)
	}
	return bp.server.sendToAdapter(rc.Platform, map[string]any{
		"type":        "reply",
		"session_key": rc.SessionKey,
		"reply_ctx":   rc.ReplyCtx,
		"content":     content,
		"format":      "text",
	})
}

func (bp *BridgePlatform) Send(ctx context.Context, replyCtx any, content string) error {
	return bp.Reply(ctx, replyCtx, content)
}

func (bp *BridgePlatform) ReconstructReplyCtx(sessionKey string) (any, error) {
	platform := bp.server.platformFromSessionKey(sessionKey)
	if platform == "" {
		return nil, fmt.Errorf("bridge: cannot determine adapter from session key %q", sessionKey)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Always obtain replyCtx from the same Platform instance's send/reply path (or from ReconstructReplyCtx on the same BridgePlatform); never reuse contexts across platforms.
  2. If the context was persisted, call ReconstructReplyCtx(sessionKey) to regenerate a valid context instead of unmarshalling the old one yourself.
  3. Log the %T of the value you are passing and confirm it matches the platform adapter that produced the outgoing message.

Example fix

// before
err := bridgePlatform.Reply(ctx, oldPersistedCtx, "hello") // oldPersistedCtx is a raw string

// after
ctxAny, err := bridgePlatform.ReconstructReplyCtx(sessionKey)
if err != nil { return err }
err = bridgePlatform.Reply(ctx, ctxAny, "hello")
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := replyCtx.(*bridgeReplyCtx); !ok {
    return fmt.Errorf("replyCtx must come from this bridge platform, got %T", replyCtx)
}

Type guard

func isBridgeReplyCtx(v any) bool { _, ok := v.(*bridgeReplyCtx); return ok }

Try / catch

if err := bp.Reply(ctx, replyCtx, content); err != nil {
    if strings.Contains(err.Error(), "invalid reply context type") {
        // regenerate via ReconstructReplyCtx and retry once
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/13ba0fdbde22040e. Report an issue: GitHub.