chenhg5/cc-connect · error

qqbot: SendWithButtons: invalid reply context type %T

Error message

qqbot: SendWithButtons: invalid reply context type %T

What it means

SendWithButtons implements core.InlineButtonSender and expects replyCtx to be a *replyContext internal to the qqbot platform. Any other type (a context from a different platform, a string, nil, etc.) triggers this error (platform/qqbot/qqbot.go:429). It is a defensive type check at the platform boundary.

Source

Thrown at platform/qqbot/qqbot.go:429

		"media":    map[string]any{"file_info": fileInfo},
	}
	if rctx.eventMsgID != "" {
		body["msg_id"] = rctx.eventMsgID
		body["msg_seq"] = p.nextMsgSeq(rctx.eventMsgID)
	}

	return p.apiRequest("POST", url, body)
}

var _ core.FileSender = (*Platform)(nil)
var _ core.InlineButtonSender = (*Platform)(nil)

// SendWithButtons sends a message with QQ Bot inline keyboard buttons.
// Implements core.InlineButtonSender.
func (p *Platform) SendWithButtons(ctx context.Context, replyCtx any, content string, buttons [][]core.ButtonOption) error {
	rctx, ok := replyCtx.(*replyContext)
	if !ok {
		return fmt.Errorf("qqbot: SendWithButtons: invalid reply context type %T", replyCtx)
	}

	// Use session key from replyContext to embed in button_data
	sessionKey := rctx.sessionKey
	if sessionKey == "" {
		return fmt.Errorf("qqbot: empty session key in reply context")
	}

	// Build QQ Bot keyboard rows from button options
	var rows []map[string]any
	for i, row := range buttons {
		var btns []map[string]any
		for j, btn := range row {
			// Encode decision + session key into button_data so we can route
			// the INTERACTION_CREATE event back to the right session.
			// btn.Data is already "perm:allow", "perm:deny", or "perm:allow_all"
			buttonData := btn.Data + ":" + sessionKey

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Only pass the replyCtx value the engine gave you for a message that arrived via the qqbot platform.
  2. Verify which platform produced the replyCtx before dispatching to a platform-specific sender.
  3. Guard with a type assertion yourself if you hold an `any` and skip the call when it is not the qqbot context.

Example fix

// before
for _, p := range platforms { p.(core.InlineButtonSender).SendWithButtons(ctx, anyReplyCtx, text, btns) }
// after
if _, ok := anyReplyCtx.(*qqbot.ReplyContextLike); ok {
    sender.(core.InlineButtonSender).SendWithButtons(ctx, anyReplyCtx, text, btns)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := replyCtx.(*replyContext); !ok {
    return fmt.Errorf("not a qqbot reply context: %T", replyCtx)
}

Type guard

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

Try / catch

if err := sender.SendWithButtons(ctx, replyCtx, text, buttons); err != nil {
    if strings.Contains(err.Error(), "invalid reply context type") {
        slog.Warn("wrong platform replyCtx for qqbot sender", "type", fmt.Sprintf("%T", replyCtx))
    }
}

Prevention

When it happens

Trigger: Calling SendWithButtons on the qqbot Platform while passing a replyCtx value obtained from a different platform's adapter, or a hand-made value that is not *qqbot.replyContext.

Common situations: Mixing reply contexts across platforms in custom engine/bridge code; storing replyCtx generically and retrieving the wrong one; calling SendWithButtons with nil after a failed lookup.

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/50b0720e025f8ae1. Report an issue: GitHub.