chenhg5/cc-connect · error

%s: chatID is empty, cannot send card

Error message

%s: chatID is empty, cannot send card

What it means

feishu: chatID is empty, cannot send card is raised in ReplyCard when the reply context lacks a chat ID and the thread/reply API path is not applicable. Without a chat ID, the card cannot be delivered to any Feishu conversation. It signals an upstream session/event wiring problem rather than an API failure.

Source

Thrown at platform/feishu/card.go:30

	larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
	larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
)

func plainText(content string) map[string]any {
	return map[string]any{"tag": "plain_text", "content": content}
}

// ReplyCard sends a structured card as a reply to the original message.
func (p *interactivePlatform) ReplyCard(ctx context.Context, rctx any, card *core.Card) error {
	rc, ok := rctx.(replyContext)
	if !ok {
		return fmt.Errorf("%s: invalid reply context type %T", p.tag(), rctx)
	}

	cardJSON := renderCard(card, rc.sessionKey)
	if !p.shouldUseThreadOrReplyAPI(rc) {
		if rc.chatID == "" {
			return fmt.Errorf("%s: chatID is empty, cannot send card", p.tag())
		}
		return p.createMessage(ctx, rc.chatID, larkim.MsgTypeInteractive, cardJSON, "send card")
	}
	return p.replyMessage(ctx, rc, larkim.MsgTypeInteractive, cardJSON)
}

// SendCard sends a structured card as a new message to the chat.
func (p *interactivePlatform) SendCard(ctx context.Context, rctx any, card *core.Card) error {
	rc, ok := rctx.(replyContext)
	if !ok {
		return fmt.Errorf("%s: invalid reply context type %T", p.tag(), rctx)
	}
	if rc.chatID == "" {
		return fmt.Errorf("%s: chatID is empty, cannot send card", p.tag())
	}

	if !p.noReplyToTrigger && p.shouldReplyInThread(rc) {
		return p.ReplyCard(ctx, rctx, card)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Verify the incoming Feishu event contains chat_id and that event parsing populates replyContext.ChatID
  2. Ensure ReplyCard is only invoked with contexts from actual received messages
  3. Fall back to SendCard with an explicit chat ID when known
  4. Update feishu/lark SDK if the event schema changed

Example fix

// before
err := p.ReplyCard(ctx, rc, card) // rc.chatID == ""
// after
if rc.chatID == "" {
    rc.chatID = p.defaultChatID // or resolve from session store
}
err := p.ReplyCard(ctx, rc, card)
Defensive patterns

Strategy: validation

Validate before calling

if rc.chatID == "" { return errors.New("cannot reply card: chat ID missing in reply context") }

Try / catch

if err := p.ReplyCard(ctx, rc, card); err != nil && strings.Contains(err.Error(), "chatID is empty") {
    // fall back to SendCard with a resolved chat ID
}

Prevention

When it happens

Trigger: ReplyCard (card.go:30) with a replyContext whose chatID field is empty while shouldUseThreadOrReplyAPI returns false — e.g. event payload missing chat_id, or a reply context synthesized without it.

Common situations: Feishu event schema change or p2p chat with unusual message type; a custom event handler constructing replyContext without populating ChatID; card sent outside a message-event flow.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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