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
- Verify the incoming Feishu event contains chat_id and that event parsing populates replyContext.ChatID
- Ensure ReplyCard is only invoked with contexts from actual received messages
- Fall back to SendCard with an explicit chat ID when known
- 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
- Validate event payloads include chat_id at parse time
- Never construct replyContext outside the platform's event handler
- Log and inspect Feishu event JSON when chatID is unexpectedly empty
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
- %s: no tracked card messageID for session %q
- app_id/app_secret are required
- invalid remote image URL
- too many redirects
- redirected to unsupported image URL
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/7c95c5e7fba0d674.
Report an issue: GitHub.