chenhg5/cc-connect · error

wecom-ws: chatID is empty, cannot send image

Error message

wecom-ws: chatID is empty, cannot send image

What it means

After the reply context passes the type check, SendImage verifies that wsReplyContext.chatID is non-empty because the WeCom WebSocket media-send API requires a target chat id. This error means a correctly typed reply context was passed, but its chatID field was never populated. The platform refuses to send to an empty destination rather than issuing a doomed API call.

Source

Thrown at platform/wecom/websocket_outbound_media.go:28

	"path/filepath"
	"strings"

	"github.com/chenhg5/cc-connect/core"
)

const (
	wecomWSUploadChunkSize = 512 * 1024
	wecomWSUploadMaxChunks = 100
)

// SendImage uploads and sends an image through the WeCom AI Bot WebSocket API.
func (p *WSPlatform) SendImage(ctx context.Context, rctx any, img core.ImageAttachment) error {
	rc, ok := rctx.(wsReplyContext)
	if !ok {
		return fmt.Errorf("wecom-ws: SendImage: invalid reply context type %T", rctx)
	}
	if rc.chatID == "" {
		return fmt.Errorf("wecom-ws: chatID is empty, cannot send image")
	}
	if len(img.Data) == 0 {
		return fmt.Errorf("wecom-ws: image data is empty")
	}

	mediaID, err := p.uploadWSMedia(ctx, "image", wsImageFileName(img), img.Data)
	if err != nil {
		return fmt.Errorf("wecom-ws: send image: %w", err)
	}
	if err := p.sendWSMediaMessage(ctx, rc.chatID, "image", mediaID); err != nil {
		return fmt.Errorf("wecom-ws: send image: %w", err)
	}
	return nil
}

func (p *WSPlatform) uploadWSMedia(ctx context.Context, mediaType, filename string, data []byte) (string, error) {
	totalChunks := (len(data) + wecomWSUploadChunkSize - 1) / wecomWSUploadChunkSize
	if totalChunks == 0 {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Populate chatID from the inbound message before replying; do not pass a zero-value wsReplyContext.
  2. Guard the call site: skip media sends when the originating message has no chatid.
  3. Check upstream message parsing — if chatid is missing from real inbound messages, fix the parsing layer rather than working around it.
  4. In tests, construct the context with a non-empty chatID.

Example fix

// before
rc := wsReplyContext{} // chatID empty
err := platform.SendImage(ctx, rc, img)
// after
rc := wsReplyContext{chatID: msg.ChatID}
if rc.chatID == "" { return nil } // skip or handle upstream
err := platform.SendImage(ctx, rc, img)
Defensive patterns

Strategy: validation

Validate before calling

// caller-side, before invoking SendImage on a context you own
if chatID == "" {
    return errors.New("cannot send image: chat id is empty")
}

Try / catch

if err := platform.SendImage(ctx, rctx, img); err != nil {
    if strings.Contains(err.Error(), "chatID is empty") {
        // drop the send or request the user re-trigger from a valid chat
    }
}

Prevention

When it happens

Trigger: Calling SendImage with a wsReplyContext whose chatID field is the empty string — e.g. a zero-value context, a context built from an inbound message that lacked a chat id, or a context explicitly cleared/reset before the send.

Common situations: Zero-value struct literals in tests (`wsReplyContext{}`); inbound WeCom messages of a type that does not carry a chatid and whose context was still used for media replies; race where a session/reply context is reset by /new or session switch before a queued image send executes.

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