chenhg5/cc-connect · error

max: unexpected replyCtx type %T

Error message

max: unexpected replyCtx type %T

What it means

SendImage implements core.ImageSender and expects replyCtx to be the platform's internal replyContext type (obtained from messages handled by this platform). Passing any other value returns this type-mismatch error.

Solutions

  1. Only pass the replyCtx that this MAX platform itself handed to your handler.
  2. Verify replyCtx is max's replyContext via a type assertion before calling SendImage.
  3. Ensure session storage serializes/deserializes the context without changing its type.

Example fix

// before
p.SendImage(ctx, someOtherPlatformCtx, img)
// after
if _, ok := someCtx.(replyContext); ok { p.SendImage(ctx, someCtx, img) }
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := replyCtx.(replyContext); !ok { return errors.New("replyCtx is not a max replyContext") }

Type guard

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

Try / catch

if err := p.SendImage(ctx, replyCtx, img); err != nil {
    if strings.Contains(err.Error(), "unexpected replyCtx type") {
        // wrong adapter's context: route to the correct platform
    }
}

Prevention

When it happens

Trigger: Calling SendImage with a replyCtx produced by a different platform, a manually constructed value, or a stale/generic reply context (e.g. nil or a string).

Common situations: Routing reply contexts across platform adapters in a multi-platform setup; persisting replyCtx in a session store and reloading it as the wrong type.

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/09e71c7df2f49add. Report an issue: GitHub.

Appendix: source

Thrown at platform/max/max.go:420

	for _, row := range buttons {
		maxRow := make([]maxButton, 0, len(row))
		for _, btn := range row {
			maxRow = append(maxRow, maxButton{
				Type:    "callback",
				Text:    btn.Text,
				Payload: btn.Data,
			})
		}
		maxButtons = append(maxButtons, maxRow)
	}
	return p.sendText(ctx, replyCtx, content, maxButtons)
}

// SendImage 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("max: unexpected replyCtx type %T", replyCtx)
	}
	token, err := p.uploadAttachment(ctx, "image", img.Data, img.FileName)
	if err != nil {
		return fmt.Errorf("max: upload image: %w", err)
	}
	body := &maxSendBody{
		Attachments: []maxOutAttachment{{
			Type:    "image",
			Payload: maxTokenPayload{Token: token},
		}},
	}
	return p.postMessage(ctx, rctx.chatID, body)
}

// SendFile implements core.FileSender. MAX routes images uploaded via the file
// endpoint as type="file" in the message, so we honor the declared kind: if the
// mime says image/*, we upload as image so the recipient sees a proper image
// preview instead of a generic file card.

View on GitHub (pinned to 4000b2338a)