hyperledger/fabric · error
Undefined tag
Error message
Undefined tag
What it means
IsTagLegal validates that a GossipMessage's Tag matches its inner message type before the gossip layer sends it. Every GossipMessage must carry a non-UNDEFINED tag; sending with Tag == GossipMessage_UNDEFINED is rejected immediately with this error.
Source
Thrown at gossip/protoext/message.go:131
func IsHelloMsg(m *gossip.GossipMessage) bool {
return m.GetHello() != nil
}
// IsDigestMsg returns whether this GossipMessage is a digest message
func IsDigestMsg(m *gossip.GossipMessage) bool {
return m.GetDataDig() != nil
}
// IsLeadershipMsg returns whether this GossipMessage is a leadership (leader election) message
func IsLeadershipMsg(m *gossip.GossipMessage) bool {
return m.GetLeadershipMsg() != nil
}
// IsTagLegal checks the GossipMessage tags and inner type
// and returns an error if the tag doesn't match the type.
func IsTagLegal(m *gossip.GossipMessage) error {
if m.Tag == gossip.GossipMessage_UNDEFINED {
return fmt.Errorf("Undefined tag")
}
if IsDataMsg(m) {
if m.Tag != gossip.GossipMessage_CHAN_AND_ORG {
return fmt.Errorf("Tag should be %s", gossip.GossipMessage_Tag_name[int32(gossip.GossipMessage_CHAN_AND_ORG)])
}
return nil
}
if IsAliveMsg(m) || m.GetMemReq() != nil || m.GetMemRes() != nil {
if m.Tag != gossip.GossipMessage_EMPTY {
return fmt.Errorf("Tag should be %s", gossip.GossipMessage_Tag_name[int32(gossip.GossipMessage_EMPTY)])
}
return nil
}
if IsIdentityMsg(m) {
if m.Tag != gossip.GossipMessage_ORG_ONLY {
return fmt.Errorf("Tag should be %s", gossip.GossipMessage_Tag_name[int32(gossip.GossipMessage_ORG_ONLY)])View on GitHub (pinned to 2736b63f8f)
Solutions
- Set the correct Tag for the message type (e.g. CHAN_AND_ORG for data, EMPTY for alive/membership, ORG_ONLY for identity) before sending.
- Use protoext's helper constructors/ext wrappers that populate Tag automatically.
- If the message came off the wire, validate before use and drop/reject it (that is what validateMsg does).
- Add a unit test asserting IsTagLegal(m) == nil for every message your component sends.
Example fix
// before
msg := &gossip.GossipMessage{ Payload: ... }
gossipSvc.Gossip(protoext.NoopSign(msg))
// after
msg := &gossip.GossipMessage{ Tag: gossip.GossipMessage_CHAN_AND_ORG, Payload: ... }
if err := protoext.IsTagLegal(msg); err != nil { return err }
gossipSvc.Gossip(protoext.NoopSign(msg)) Defensive patterns
Strategy: validation
Validate before calling
func validGossipMessage(m *gossip.GossipMessage) bool {
return m != nil && m.Tag != gossip.GossipMessage_UNDEFINED && protoext.IsTagLegal(m) == nil
}
// guard before send:
if !validGossipMessage(msg) { return errors.New("refusing to send invalid gossip message") } Type guard
func isTagged(m *gossip.GossipMessage) bool {
return m != nil && m.Tag != gossip.GossipMessage_UNDEFINED
} Try / catch
if err := protoext.IsTagLegal(msg); err != nil {
log.Warningf("dropping message with illegal tag: %v", err)
return
} Prevention
- Always set Tag explicitly when constructing GossipMessages.
- Run IsTagLegal on outgoing messages in unit tests.
- Use shared constructors/wrappers instead of raw struct literals.
- Keep validateMsg in the send path enabled to catch regressions.
When it happens
Trigger: Calling protoext.IsTagLegal (directly or via validateMsg/Gossip send path) with a GossipMessage whose Tag field was left at its zero value GossipMessage_UNDEFINED.
Common situations: Constructing a GossipMessage by hand and forgetting to set Tag; a proto message deserialized from an untrusted/partial source; tests building minimal messages without setting the tag.
Related errors
- block from orderer could not be re-marshaled: proto: Marshal
- expected collection config of type CollectionConfig_StaticCo
- Tag should be %s
- Failed unmarshalling GossipMessage from envelope: %v
- malformed org definition for org: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/a75037cc73819fd4.
Report an issue: GitHub.