larksuite/cli · error

protocol: unknown message type %q

Error message

protocol: unknown message type %q

What it means

protocol.Decode parsed the JSON envelope but its 'type' field does not match any known message type constant (Hello, Event, StatusResponse, Shutdown, SourceStatus), so no target struct exists to unmarshal into. This guards the protocol against version skew and garbage-with-valid-JSON frames.

Source

Thrown at internal/event/adapter/localbus/protocol/codec.go:116

		msg = &HelloAck{}
	case MsgTypeEvent:
		msg = &Event{}
	case MsgTypeBye:
		msg = &Bye{}
	case MsgTypePreShutdownCheck:
		msg = &PreShutdownCheck{}
	case MsgTypePreShutdownAck:
		msg = &PreShutdownAck{}
	case MsgTypeStatusQuery:
		msg = &StatusQuery{}
	case MsgTypeStatusResponse:
		msg = &StatusResponse{}
	case MsgTypeShutdown:
		msg = &Shutdown{}
	case MsgTypeSourceStatus:
		msg = &SourceStatus{}
	default:
		return nil, fmt.Errorf("protocol: unknown message type %q", env.Type)
	}

	if err := json.Unmarshal(line, msg); err != nil {
		return nil, fmt.Errorf("protocol decode %s: %w", env.Type, err)
	}
	return msg, nil
}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Log the %q type value from the error and compare against the sender's protocol constants
  2. Upgrade/downgrade so both bus and client use the same lark-cli version (protocol mismatch is the usual cause)
  3. Fix the sender to use the exported MsgType* constants instead of string literals
  4. If forward-compatibility is needed, have the reader ignore unknown types instead of failing the connection

Example fix

// before
conn.Write([]byte(`{"type":"Ping"}`))
// after
protocol.Encode(conn, &protocol.Hello{}) // uses MsgTypeHello constant
Defensive patterns

Strategy: type-guard

Validate before calling

func knownType(line []byte) bool {
	var env struct{ Type string `json:"type"` }
	if json.Unmarshal(line, &env) != nil {
		return false
	}
	switch env.Type {
	case protocol.MsgTypeHello, protocol.MsgTypeEvent,
		protocol.MsgTypeStatusResponse, protocol.MsgTypeShutdown,
		protocol.MsgTypeSourceStatus:
		return true
	}
	return false
}

Type guard

func isUnknownTypeError(err error) bool {
	return err != nil && strings.HasPrefix(err.Error(), "protocol: unknown message type")
}

Try / catch

msg, err := protocol.Decode(line)
if err != nil {
	if isUnknownTypeError(err) {
		log.Printf("ignoring unknown message from peer: %v", err)
		return nil // skip frame; keep connection alive
	}
	return err
}

Prevention

When it happens

Trigger: Decode reads a line whose JSON has a 'type' value outside the known set — a peer on a newer/older protocol version, a typo'd type string, or a foreign JSON line reaching the bus stream.

Common situations: CLI and long-running bus binary updated to different versions (old bus doesn't know new message types); hand-crafted test/status probes sending wrong type; another process writing unrelated JSON into the same file/socket.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/a6316933b7b0c2c6. Report an issue: GitHub.