chenhg5/cc-connect · error

dingtalk: invalid conversation type

Error message

dingtalk: invalid conversation type %q in session key: %q

What it means

The session key parsed into enough segments, but the conversation type segment is neither 'g' (group) nor 'd' (direct/1:1) — the only two convTypes the DingTalk adapter emits. The key is not one this platform produced, so reconstruction is refused.

Solutions

  1. Use only 'g' for group conversations or 'd' for direct 1:1 conversations in the second segment.
  2. Check adapter version history — if keys were generated by an older/newer version, migrate them to the g/d scheme.
  3. Re-capture the key from a real incoming message (the adapter builds it as dingtalk:g:<cid> or dingtalk:d:<cid>:<staffId>).
  4. Grep your persistence layer for dingtalk:* keys whose second segment is not g/d and fix or drop them.

Example fix

// before
sessionKey := "dingtalk:group:cid123" // wrong convType
rc, err := platform.ReconstructReplyCtx(sessionKey)
// after
sessionKey := "dingtalk:g:cid123" // 'g' = group, 'd' = direct
rc, err := platform.ReconstructReplyCtx(sessionKey)
Defensive patterns

Strategy: validation

Validate before calling

func hasValidConvType(key string) bool {
    rest := strings.TrimPrefix(key, "dingtalk:")
    parts := strings.SplitN(rest, ":", 3)
    return len(parts) >= 1 && (parts[0] == "g" || parts[0] == "d")
}
// guard before reconstruction
if !hasValidConvType(sessionKey) {
    return fmt.Errorf("convType must be 'g' or 'd'")
}

Type guard

func isKnownConvType(t string) bool {
    return t == "g" || t == "d"
}

Try / catch

ctx, err := platform.ReconstructReplyCtx(sessionKey)
if err != nil {
    if strings.Contains(err.Error(), "invalid conversation type") {
        slog.Error("unknown convType in dingtalk key; regenerate from live message", "key", sessionKey)
        return errBadConvType
    }
    return err
}

Prevention

When it happens

Trigger: A session key like 'dingtalk:x:cid123' where the convType slot holds an arbitrary string; keys from a different adapter version that used different convType letters; typos in hand-constructed keys.

Common situations: Hand-building keys after reading an outdated doc or code sample; mixing keys from a forked/modified adapter; automated migrations writing placeholder convTypes.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at platform/dingtalk/dingtalk.go:1619

// ReconstructReplyCtx implements core.ReplyContextReconstructor.
// Session key format: "dingtalk:{convType}:{conversationId}:{senderStaffId}" or "dingtalk:{convType}:{conversationId}"
// where convType is "g" (group) or "d" (direct/1:1).
func (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {
	if !strings.HasPrefix(sessionKey, "dingtalk:") {
		return nil, fmt.Errorf("dingtalk: not a dingtalk session key: %q", sessionKey)
	}

	stripped := strings.TrimPrefix(sessionKey, "dingtalk:")
	parts := strings.SplitN(stripped, ":", 3)

	if len(parts) < 2 {
		return nil, fmt.Errorf("dingtalk: invalid session key format: %q", sessionKey)
	}

	convType := parts[0]
	if convType != "g" && convType != "d" {
		return nil, fmt.Errorf("dingtalk: invalid conversation type %q in session key: %q", convType, sessionKey)
	}

	conversationId := parts[1]
	if conversationId == "" {
		return nil, fmt.Errorf("dingtalk: empty conversationId in session key: %q", sessionKey)
	}

	var senderStaffId string
	if len(parts) > 2 {
		senderStaffId = parts[2]
	}

	return replyContext{
		conversationId: conversationId,
		senderStaffId:  senderStaffId,
		isGroup:        convType == "g",
		proactive:      true,
	}, nil

View on GitHub (pinned to 4000b2338a)