chenhg5/cc-connect · error

%s: chatID is empty, cannot send new message

Error message

%s: chatID is empty, cannot send new message

What it means

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.

Source

Thrown at platform/feishu/feishu.go:4031

func (p *Platform) shouldReplyInThread(rc replyContext) bool {
	if rc.messageID == "" {
		return false
	}
	return p.threadIsolation && isThreadSessionKey(rc.sessionKey)
}

// shouldUseThreadOrReplyAPI is true when we should call Im.Message.Reply (optionally with ReplyInThread).
func (p *Platform) shouldUseThreadOrReplyAPI(rc replyContext) bool {
	if rc.messageID == "" {
		return false
	}
	return !p.noReplyToTrigger
}

func (p *Platform) sendNewMessageToChat(ctx context.Context, rc replyContext, msgType, content string) error {
	if rc.chatID == "" {
		return fmt.Errorf("%s: chatID is empty, cannot send new message", p.tag())
	}
	return p.createMessage(ctx, rc.chatID, msgType, content, "send")
}

func (p *Platform) buildReplyMessageReqBody(rc replyContext, msgType, content string) *larkim.ReplyMessageReqBody {
	body := larkim.NewReplyMessageReqBodyBuilder().
		MsgType(msgType).
		Content(content)
	if p.shouldReplyInThread(rc) {
		body.ReplyInThread(true)
	}
	return body.Build()
}

func (p *Platform) replyMessage(ctx context.Context, rc replyContext, msgType, content string) error {
	req := larkim.NewReplyMessageReqBuilder().
		MessageId(rc.messageID).
		Body(p.buildReplyMessageReqBody(rc, msgType, content)).

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Log the raw incoming event to confirm whether chat_id is present in the payload.
  2. Check how replyContext is populated (event extraction) and fix the field mapping for the message type in question.
  3. Skip sendNewMessageToChat and fall back to reply-message mode when chatID is empty.
  4. Pin/upgrade the lark SDK to a version whose event schema matches the parsing code.

Example fix

// before
if rc.chatID == "" {
	return fmt.Errorf("%s: chatID is empty, cannot send new message", p.tag())
}
// after
if rc.chatID == "" {
	slog.Warn(p.tag()+": chatID empty, falling back to reply mode")
	return p.replyMessage(ctx, rc, msgType, content)
}
Defensive patterns

Strategy: validation

Validate before calling

if rc.chatID == "" {
	return errors.New("cannot send: chatID is empty")
}
if err := sendNewMessageToChat(ctx, rc, msgType, content); err != nil { ... }

Type guard

func canSendNewMessage(rc replyContext) bool { return rc.chatID != "" }

Try / catch

if err := p.sendNewMessageToChat(ctx, rc, msgType, content); err != nil {
	if strings.Contains(err.Error(), "chatID is empty") {
		// fall back to reply path
		return p.replyMessage(ctx, rc, msgType, content)
	}
	return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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/70be978b92122684. Report an issue: GitHub.