larksuite/cli · error
protocol decode %s: %w
Error message
protocol decode %s: %w
What it means
Decode in internal/event/adapter/localbus/protocol/codec.go wraps a json.Unmarshal failure that occurs while decoding the payload of a recognized localbus envelope message type. The envelope was parsed and its type was known (e.g. SourceStatus), but the JSON body did not match the expected struct. The wrapper preserves the envelope type and the underlying JSON error cause.
Source
Thrown at internal/event/adapter/localbus/protocol/codec.go:120
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
- Log the wrapped cause (%w) to see the exact field/type mismatch, then inspect the raw line for the offending field
- Verify all bus producers and consumers use the same protocol version / generated structs
- Re-encode the frame with this library's Encode so it matches the canonical struct shape
- Add a regression test (see TestEncodeDecode*) round-tripping the message to catch drift
Example fix
// before
msg, err := protocol.Decode(line)
if err != nil { return err } // opaque
// after
msg, err := protocol.Decode(line)
if err != nil {
return fmt.Errorf("decode localbus frame: %w", err) // cause names the bad field
} Defensive patterns
Strategy: try-catch
Validate before calling
if !json.Valid(frame) { return fmt.Errorf("frame is not valid JSON") } Type guard
func isDecodeError(err error) bool { return err != nil && strings.Contains(err.Error(), "protocol decode ") } Try / catch
msg, err := protocol.Decode(line)
if err != nil {
var jsonErr *json.UnmarshalTypeError
if errors.As(err, &jsonErr) {
log.Printf("bad field %s in frame type", jsonErr.Field)
}
return fmt.Errorf("skip malformed frame: %w", err)
} Prevention
- Always produce frames via Encode, never hand-written JSON
- Pin all bus producers/consumers to the same protocol version
- Round-trip test new message types like TestEncodeDecodeEvent
- Log the full wrapped error, not just the wrapper text
When it happens
Trigger: Decode() receives a line whose envelope type maps to a concrete struct (e.g. &SourceStatus{}) but json.Unmarshal(line, msg) fails because the body has fields with wrong types (string where number expected), malformed JSON, or null where a struct is required.
Common situations: A producer on the bus was built with a different protocol version and serializes fields with changed types; a corrupted or truncated frame on the local transport; a test or custom peer hand-writes frames that do not match the canonical struct encoding.
Related errors
- protocol: frame exceeds MaxFrameBytes
- app registration failed: response missing device_code
- lark-cli stdout was not JSON: {snippet}
- lark-cli returned a non-object JSON payload
- malformed config
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/6f296a0fe0bdf31c.
Report an issue: GitHub.