chenhg5/cc-connect · error

qq: SendImage: invalid reply context type %T

Error message

qq: SendImage: invalid reply context type %T

What it means

Returned by Platform.SendImage (the core.ImageSender implementation) when replyCtx is not a *replyContext. Same contract as Send: the image sender only accepts the internal reply context pointer produced for a previously received QQ message, and reports the offending type (%T) to ease diagnosis.

Source

Thrown at platform/qq/qq.go:472

	}

	if rctx.messageType == "group" {
		params["group_id"] = rctx.groupID
		_, err := p.callAPI("send_group_msg", params)
		return err
	}

	params["user_id"] = rctx.userID
	_, err := p.callAPI("send_private_msg", params)
	return err
}

// SendImage sends an image to the conversation.
// Implements core.ImageSender.
func (p *Platform) SendImage(ctx context.Context, replyCtx any, img core.ImageAttachment) error {
	rctx, ok := replyCtx.(*replyContext)
	if !ok {
		return fmt.Errorf("qq: SendImage: invalid reply context type %T", replyCtx)
	}

	b64 := base64.StdEncoding.EncodeToString(img.Data)
	segments := []map[string]any{
		{"type": "image", "data": map[string]any{"file": "base64://" + b64}},
	}

	params := map[string]any{
		"message": segments,
	}

	if rctx.messageType == "group" {
		params["group_id"] = rctx.groupID
		_, err := p.callAPI("send_group_msg", params)
		if err != nil {
			return fmt.Errorf("qq: send image: %w", err)
		}
		return nil

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Pass the original *replyContext delivered with the inbound QQ message.
  2. Check the %T in the message: it names the actual type you passed — correct it to the platform's reply context pointer type.
  3. If routing across platforms, re-derive the context from a message received by the qq Platform, not a foreign one.
  4. Guard with a type assertion before calling SendImage if the context comes from untyped storage.

Example fix

// before
platform.SendImage(ctx, map[string]any{"group_id": 123}, img)

// after
platform.SendImage(ctx, replyCtx, img) // replyCtx from inbound message events
Defensive patterns

Strategy: type-guard

Type guard

func validImageTarget(replyCtx any) bool {
    _, ok := replyCtx.(*replyContext)
    return ok
}

Try / catch

if err := p.SendImage(ctx, replyCtx, img); err != nil {
    if strings.Contains(err.Error(), "invalid reply context type") {
        slog.Error("SendImage got non-qq context", "type", fmt.Sprintf("%T", replyCtx))
    }
    return err
}

Prevention

When it happens

Trigger: Calling SendImage(ctx, replyCtx, img) with nil, a string/int conversation ID, a map-based context, a value-type replyContext, or a context from another platform.

Common situations: Forwarding a reply context received from Telegram/Feishu into the QQ adapter; decoding a stored JSON blob back into map[string]any and passing it; passing the core.Message object itself instead of its reply context field.

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/396c412ca3b188ba. Report an issue: GitHub.