hyperledger/fabric · error

Tag should be %s

Error message

Tag should be %s

What it means

IsTagLegal requires a data message (IsDataMsg) to carry the CHAN_AND_ORG tag so the message is disseminated only to channel members of the same org. A data message tagged with anything else is rejected with this formatted error naming the expected tag.

Source

Thrown at gossip/protoext/message.go:135

// 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)])
		}
		return nil
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Set msg.Tag = gossip.GossipMessage_CHAN_AND_ORG on all data messages before sending.
  2. Run IsTagLegal on outgoing messages in tests to catch mismatches early.
  3. If receiving this on the wire, the remote peer is misconfigured/malicious; rely on validateMsg to drop the message.
  4. Check that the payload type actually is a data message; if not, fix the message construction.

Example fix

// before
m := &gossip.GossipMessage{Content: &gossip.GossipMessage_DataMsg{DataMsg: d}}
// after
m := &gossip.GossipMessage{
    Tag: gossip.GossipMessage_CHAN_AND_ORG,
    Content: &gossip.GossipMessage_DataMsg{DataMsg: d},
}
Defensive patterns

Strategy: validation

Validate before calling

func makeDataMsg(d *gossip.DataMessage) *gossip.GossipMessage {
    return &gossip.GossipMessage{
        Tag: gossip.GossipMessage_CHAN_AND_ORG,
        Content: &gossip.GossipMessage_DataMsg{DataMsg: d},
    }
}

Type guard

func isLegallyTaggedDataMsg(m *gossip.GossipMessage) bool {
    return protoext.IsDataMsg(m) && m.Tag == gossip.GossipMessage_CHAN_AND_ORG
}

Try / catch

if err := protoext.IsTagLegal(msg); err != nil {
    log.Warningf("illegal data message tag: %v", err)
    return
}

Prevention

When it happens

Trigger: Sending/gossiping a GossipMessage that IsDataMsg classifies as a data message (HasDataMsg payload) but whose Tag != GossipMessage_CHAN_AND_ORG; caught by validateMsg on send in the Gossip service or by tests.

Common situations: Hand-crafted DataMsg built with Tag EMPTY, UNDEFINED, or ORG_ONLY; a refactor changed the payload but not the tag; interop with a peer producing malformed data messages.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/9a251ed33bb55480. Report an issue: GitHub.