{"record":{"id":"70be978b92122684","repo":"chenhg5/cc-connect","slug":"s-chatid-is-empty-cannot-send-new-message","errorCode":null,"errorMessage":"%s: chatID is empty, cannot send new message","messagePattern":"(.+?): chatID is empty, cannot send new message","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/feishu.go","lineNumber":4031,"sourceCode":"\nfunc (p *Platform) shouldReplyInThread(rc replyContext) bool {\n\tif rc.messageID == \"\" {\n\t\treturn false\n\t}\n\treturn p.threadIsolation && isThreadSessionKey(rc.sessionKey)\n}\n\n// shouldUseThreadOrReplyAPI is true when we should call Im.Message.Reply (optionally with ReplyInThread).\nfunc (p *Platform) shouldUseThreadOrReplyAPI(rc replyContext) bool {\n\tif rc.messageID == \"\" {\n\t\treturn false\n\t}\n\treturn !p.noReplyToTrigger\n}\n\nfunc (p *Platform) sendNewMessageToChat(ctx context.Context, rc replyContext, msgType, content string) error {\n\tif rc.chatID == \"\" {\n\t\treturn fmt.Errorf(\"%s: chatID is empty, cannot send new message\", p.tag())\n\t}\n\treturn p.createMessage(ctx, rc.chatID, msgType, content, \"send\")\n}\n\nfunc (p *Platform) buildReplyMessageReqBody(rc replyContext, msgType, content string) *larkim.ReplyMessageReqBody {\n\tbody := larkim.NewReplyMessageReqBodyBuilder().\n\t\tMsgType(msgType).\n\t\tContent(content)\n\tif p.shouldReplyInThread(rc) {\n\t\tbody.ReplyInThread(true)\n\t}\n\treturn body.Build()\n}\n\nfunc (p *Platform) replyMessage(ctx context.Context, rc replyContext, msgType, content string) error {\n\treq := larkim.NewReplyMessageReqBuilder().\n\t\tMessageId(rc.messageID).\n\t\tBody(p.buildReplyMessageReqBody(rc, msgType, content)).","sourceCodeStart":4013,"sourceCodeEnd":4049,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/feishu.go#L4013-L4049","documentation":"A defensive pre-condition check in sendNewMessageToChat: the replyContext has no chatID, so a brand-new (non-reply) message cannot be addressed to any conversation. The platform tag is prefixed to make the originating adapter instance identifiable in logs.","triggerScenarios":"An event/message flow builds a replyContext from an incoming Feishu event where the chat_id (chat_id / chatId field) is absent — e.g. thread-style or special message types, or a schema change in the event payload — and then tries to send a new message instead of a threaded reply.","commonSituations":"Feishu SDK version upgrade renamed/moved the chat_id field in the event struct, message received through a channel type that omits chat_id, or a code path constructing replyContext manually without setting chatID.","solutions":["Log the raw incoming event to confirm whether chat_id is present in the payload.","Check how replyContext is populated (event extraction) and fix the field mapping for the message type in question.","Skip sendNewMessageToChat and fall back to reply-message mode when chatID is empty.","Pin/upgrade the lark SDK to a version whose event schema matches the parsing code."],"exampleFix":"// before\nif rc.chatID == \"\" {\n\treturn fmt.Errorf(\"%s: chatID is empty, cannot send new message\", p.tag())\n}\n// after\nif rc.chatID == \"\" {\n\tslog.Warn(p.tag()+\": chatID empty, falling back to reply mode\")\n\treturn p.replyMessage(ctx, rc, msgType, content)\n}","handlingStrategy":"validation","validationCode":"if rc.chatID == \"\" {\n\treturn errors.New(\"cannot send: chatID is empty\")\n}\nif err := sendNewMessageToChat(ctx, rc, msgType, content); err != nil { ... }","typeGuard":"func canSendNewMessage(rc replyContext) bool { return rc.chatID != \"\" }","tryCatchPattern":"if err := p.sendNewMessageToChat(ctx, rc, msgType, content); err != nil {\n\tif strings.Contains(err.Error(), \"chatID is empty\") {\n\t\t// fall back to reply path\n\t\treturn p.replyMessage(ctx, rc, msgType, content)\n\t}\n\treturn err\n}","preventionTips":["Assert chat_id is present when parsing every incoming Feishu event.","Add a startup test that parses sample events for each message type.","Log raw event payloads when chat_id extraction fails.","Cover the chatID extraction path with a unit test per SDK version bump."],"tags":["feishu","lark","validation","chat-id"],"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"}