chenhg5/cc-connect · error

dingtalk: invalid reply context type %T

Error message

dingtalk: invalid reply context type %T

What it means

ReplyWithAt expects its rctx parameter to be the platform-internal replyContext type (the value the platform itself produced when receiving a message). If the caller passes anything else — e.g. a reply context from another platform, a raw string, or a constructed struct of the wrong type — the type assertion fails and this error reports the actual Go type received.

Source

Thrown at platform/dingtalk/dingtalk.go:801

	if expiry <= 0 {
		slog.Warn("dingtalk: missing/invalid expireIn in token response, defaulting to 7200s", "got", tokenResp.ExpireIn)
		expiry = 7200
	}
	if expiry > 300 {
		expiry -= 300 // 5 minute buffer
	}
	p.tokenExpiry = time.Now().Add(time.Duration(expiry) * time.Second)

	slog.Debug("dingtalk: access token refreshed", "expires_at", p.tokenExpiry)
	return p.accessToken, nil
}

// ReplyWithAt sends a reply with @mention support. Uses text msgtype (not markdown)
// because only text type supports highlighted/blue @mentions in DingTalk.
func (p *Platform) ReplyWithAt(ctx context.Context, rctx any, content string, atUsers []string, atAll bool) error {
	rc, ok := rctx.(replyContext)
	if !ok {
		return fmt.Errorf("dingtalk: invalid reply context type %T", rctx)
	}
	if rc.proactive || rc.sessionWebhook == "" {
		return p.sendProactiveMessage(ctx, rc, content)
	}

	payload := map[string]any{
		"msgtype": "text",
		"text":    map[string]string{"content": content},
	}
	if len(atUsers) > 0 || atAll {
		payload["at"] = map[string]any{
			"atUserIds": atUsers,
			"isAtAll":   atAll,
		}
	}
	body, err := json.Marshal(payload)
	if err != nil {
		return fmt.Errorf("dingtalk: marshal reply: %w", err)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Only pass replyContext values originally produced by the DingTalk platform (from its receive/reply flow), never from other platform adapters.
  2. Check the reported %T in the message — if it's another platform's type, route the reply through that platform instead.
  3. Update cc-connect if contexts are persisted/serialized across versions; internal types are not stable across releases.
  4. If constructing contexts manually, use the exported APIs the platform provides instead of forging internal types.
  5. Verify via core.Engine Reply APIs rather than calling platform internals directly.

Example fix

// before: passing a foreign context
err := dingtalkPlat.ReplyWithAt(ctx, someTelegramCtx, "hi", ats, false)

// after: reply through the originating platform/engine
err := originatingPlatform.Reply(ctx, replyCtx, "hi")
Defensive patterns

Strategy: type-guard

Validate before calling

if rc, ok := rctx.(platform.replyContext); !ok {
    return fmt.Errorf("reply context of type %T is not a dingtalk replyContext", rctx)
}

Type guard

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

Try / catch

if err := p.ReplyWithAt(ctx, rctx, text, ats, false); err != nil {
    if strings.Contains(err.Error(), "invalid reply context type") {
        // fall back to the engine-level Reply which routes correctly
        return engine.Reply(ctx, rctx, text)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Platform.ReplyWithAt directly with a context obtained from a different platform adapter, from an older cc-connect version with a different internal replyContext layout, or a hand-constructed value rather than one produced by the DingTalk adapter's message receive path.

Common situations: Custom integrations that cache reply contexts across platforms, mixing adapters in one process and passing a telegram/discord reply context to the DingTalk platform, or holding a stale context after an engine restart.

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