chenhg5/cc-connect · error

yuanbao: empty conn msg

Error message

yuanbao: empty conn msg

What it means

Thrown by decodeConnMsg when handed a zero-length raw buffer: there are no fields to parse at all, so no connMsg can be produced. It's a fast-fail guard before parseFields is invoked, distinguishing 'empty payload' from 'malformed payload'.

Source

Thrown at platform/yuanbao/proto.go:264

type connHead struct {
	cmdType int
	cmd     string
	seqNo   int
	msgID   string
	module  string
	needAck bool
	status  int
}

type connMsg struct {
	head  connHead
	seqNo int
	data  []byte
}

func decodeConnMsg(raw []byte) (*connMsg, error) {
	if len(raw) == 0 {
		return nil, fmt.Errorf("yuanbao: empty conn msg")
	}
	fields, err := parseFields(raw)
	if err != nil {
		return nil, err
	}
	headBytes := getBytes(fields, 1)
	payload := getBytes(fields, 2)
	var head connHead
	if len(headBytes) > 0 {
		hf, err := parseFields(headBytes)
		if err != nil {
			return nil, fmt.Errorf("yuanbao: parse head: %w", err)
		}
		head = connHead{
			cmdType: int(getVarint(hf, 1)),
			cmd:     getString(hf, 2),
			seqNo:   int(getVarint(hf, 3)),
			msgID:   getString(hf, 4),

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check len(raw) before calling decodeConnMsg and skip/dispatch empty frames to the appropriate handler (ping/ack).
  2. Treat an empty payload in a message-expecting frame as a protocol error and log it with the frame command type from the header.
  3. If the empty buffer comes from getBytes(fields, N) returning nil for an absent field, check field presence before decoding the sub-message.
  4. Verify the server isn't sending empty bodies due to an API change; capture a frame dump to confirm.

Example fix

// before
raw := frame.Payload
cm, err := decodeConnMsg(raw)
// after
if len(frame.Payload) == 0 {
    switch frame.Cmd { // dispatch empties to heartbeat handling
    case cmdPing:
        handlePing(); return
    default:
        slog.Warn("yuanbao: empty conn msg body", "cmd", frame.Cmd)
        return
    }
}
cm, err := decodeConnMsg(frame.Payload)
Defensive patterns

Strategy: validation

Validate before calling

func shouldDecodeConnMsg(frame Frame) bool {
    return len(frame.Payload) > 0
}

Try / catch

cm, err := decodeConnMsg(raw)
if err != nil {
    if strings.Contains(err.Error(), "empty conn msg") {
        return nil // benign: heartbeat/empty frame
    }
    return err
}

Prevention

When it happens

Trigger: The transport delivered a frame whose body is empty (heartbeat/keepalive variant not handled upstream), or a caller slices a zero-length region (e.g. getBytes returned nil for a missing field 2 and that nil is re-decoded). Reached from authenticate, handleFrame, and tests.

Common situations: Handling a ping/pong or ack frame with no payload through the connMsg path; server sending an empty DATA frame; a sub-message field absent so getBytes returns nil which is then decoded.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/acb8ab88dfb7ffb6. Report an issue: GitHub.