{"record":{"id":"7c95c5e7fba0d674","repo":"chenhg5/cc-connect","slug":"s-chatid-is-empty-cannot-send-card","errorCode":null,"errorMessage":"%s: chatID is empty, cannot send card","messagePattern":"(.+?): chatID is empty, cannot send card","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/card.go","lineNumber":30,"sourceCode":"\tlarkcore \"github.com/larksuite/oapi-sdk-go/v3/core\"\n\tlarkim \"github.com/larksuite/oapi-sdk-go/v3/service/im/v1\"\n)\n\nfunc plainText(content string) map[string]any {\n\treturn map[string]any{\"tag\": \"plain_text\", \"content\": content}\n}\n\n// ReplyCard sends a structured card as a reply to the original message.\nfunc (p *interactivePlatform) ReplyCard(ctx context.Context, rctx any, card *core.Card) error {\n\trc, ok := rctx.(replyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"%s: invalid reply context type %T\", p.tag(), rctx)\n\t}\n\n\tcardJSON := renderCard(card, rc.sessionKey)\n\tif !p.shouldUseThreadOrReplyAPI(rc) {\n\t\tif rc.chatID == \"\" {\n\t\t\treturn fmt.Errorf(\"%s: chatID is empty, cannot send card\", p.tag())\n\t\t}\n\t\treturn p.createMessage(ctx, rc.chatID, larkim.MsgTypeInteractive, cardJSON, \"send card\")\n\t}\n\treturn p.replyMessage(ctx, rc, larkim.MsgTypeInteractive, cardJSON)\n}\n\n// SendCard sends a structured card as a new message to the chat.\nfunc (p *interactivePlatform) SendCard(ctx context.Context, rctx any, card *core.Card) error {\n\trc, ok := rctx.(replyContext)\n\tif !ok {\n\t\treturn fmt.Errorf(\"%s: invalid reply context type %T\", p.tag(), rctx)\n\t}\n\tif rc.chatID == \"\" {\n\t\treturn fmt.Errorf(\"%s: chatID is empty, cannot send card\", p.tag())\n\t}\n\n\tif !p.noReplyToTrigger && p.shouldReplyInThread(rc) {\n\t\treturn p.ReplyCard(ctx, rctx, card)","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/card.go#L12-L48","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nerr := p.ReplyCard(ctx, rc, card) // rc.chatID == \"\"\n// after\nif rc.chatID == \"\" {\n    rc.chatID = p.defaultChatID // or resolve from session store\n}\nerr := p.ReplyCard(ctx, rc, card)","handlingStrategy":"validation","validationCode":"if rc.chatID == \"\" { return errors.New(\"cannot reply card: chat ID missing in reply context\") }","typeGuard":null,"tryCatchPattern":"if err := p.ReplyCard(ctx, rc, card); err != nil && strings.Contains(err.Error(), \"chatID is empty\") {\n    // fall back to SendCard with a resolved chat ID\n}","preventionTips":["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"],"tags":["feishu","missing-value","card"],"backgroundTag":"empty-required-field","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}