chenhg5/cc-connect · error

tuitui: invalid chat type %q

Error message

tuitui: invalid chat type %q

What it means

reactToMessage builds the /robot/message/custom/modify payload per chat type (direct, group, channel). If rctx.chatType is none of the known constants it cannot fill the right recipient field and rejects the request before any network call. chatType is usually derived from the reply context or guessed via guessChatType(chatID), so an empty/garbage value signals a bad reply context.

Source

Thrown at platform/tuitui/tuitui.go:657

	payload := map[string]any{
		"msgtype":        "emoji_reaction",
		"tousers":        []map[string]string{},
		"togroups":       []map[string]string{},
		"toteams":        []map[string]string{},
		"emoji_reaction": map[string]any{"emoji": emoji, "cancel": false},
	}
	switch rctx.chatType {
	case chatTypeDirect:
		payload["tousers"] = []map[string]string{{"user": rctx.chatID, "msgid": rctx.messageID}}
	case chatTypeGroup:
		payload["togroups"] = []map[string]string{{"group": rctx.chatID, "msgid": rctx.messageID}}
	case chatTypeChannel:
		team := teamsParseChatID(rctx.chatID)
		team["parent_id"] = ""
		team["post_id"] = rctx.messageID
		payload["toteams"] = []map[string]string{team}
	default:
		return fmt.Errorf("tuitui: invalid chat type %q", rctx.chatType)
	}
	return p.postJSON(ctx, "/robot/message/custom/modify", payload, nil)
}

func (p *Platform) sendMediaID(ctx context.Context, rctx replyContext, mediaID, filename string, isImage bool) error {
	payload := map[string]any{}
	if rctx.chatType == chatTypeChannel {
		markdown := fmt.Sprintf("[%s]({{tuitui_file %q}})", filename, mediaID)
		if isImage {
			markdown = fmt.Sprintf("![]({{tuitui_image %q}})", mediaID)
		}
		payload["msgtype"] = "richtext/markdown"
		payload["richtext"] = map[string]string{
			"markdown":     markdown,
			"delims_left":  "{{",
			"delims_right": "}}",
		}
	} else if isImage {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Set chatType explicitly to the correct constant (chatTypeDirect/chatTypeGroup/chatTypeChannel) when building the replyContext.
  2. Ensure the chatID uses a format guessChatType can parse (correct prefix) so the fallback guess works.
  3. Log/print rctx.chatID and rctx.chatType to identify which value is being rejected, then correct it.
  4. If a new chat type exists upstream, add a case for it in reactToMessage.

Example fix

// before
rctx := replyContext{ChatID: "123"} // chatType empty, guess fails
// after
rctx := replyContext{ChatID: "grp_123", ChatType: chatTypeGroup}
Defensive patterns

Strategy: validation

Validate before calling

switch rctx.chatType {
case chatTypeDirect, chatTypeGroup, chatTypeChannel:
    // ok
default:
    return fmt.Errorf("unsupported chat type %q", rctx.chatType)
}

Prevention

When it happens

Trigger: Calling reactToMessage with a replyContext whose chatType is not one of the recognized constants (e.g. empty string when guessChatType returned nothing, or a misspelled chat type).

Common situations: Manually constructed replyContext with chatType left unset and a chatID format guessChatType does not recognize; a Tuitui API change introducing a new chat type the adapter doesn't know.

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