hyperledger/fabric · error

message isn't an alive message

Error message

message isn't an alive message

What it means

validateAliveMessage rejects a SignedGossipMessage whose GetAliveMsg() is nil, meaning the envelope's payload decoded to something other than an AliveMessage. The discovery client uses AliveMessages to learn peer membership (endpoint, identity), so it fails the peer. The error is wrapped by the endorser flow as 'failed validating alive message'.

Source

Thrown at discovery/client/client.go:577

}

type endorsementDescriptor struct {
	endorsersByGroups map[string][]*Peer
	layouts           []map[string]int
}

// NewClient creates a new Client instance
func NewClient(createConnection Dialer, s Signer, signerCacheSize uint) *Client {
	return &Client{
		createConnection: createConnection,
		signRequest:      NewMemoizeSigner(s, signerCacheSize).Sign,
	}
}

func validateAliveMessage(message *gprotoext.SignedGossipMessage) error {
	am := message.GetAliveMsg()
	if am == nil {
		return errors.New("message isn't an alive message")
	}
	m := am.Membership
	if m == nil {
		return errors.New("membership is empty")
	}
	if am.Timestamp == nil {
		return errors.New("timestamp is nil")
	}
	return nil
}

func validateStateInfoMessage(message *gprotoext.SignedGossipMessage) error {
	si := message.GetStateInfo()
	if si == nil {
		return errors.New("message isn't a stateInfo message")
	}
	if si.Timestamp == nil {
		return errors.New("timestamp is nil")

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Inspect the response: log the SignedGossipMessage type of the offending peer record
  2. Ensure the discovery target peer is a member of the requested channel and gossip is convergent (peer gossip logs show membership)
  3. Restart gossip on the target peer so membership/alive messages are regenerated
  4. Align Fabric versions across peers
  5. Retry against a different peer

Example fix

// before
peers, err := resp.ForChannel("mychannel") // fails with wrapped validation error
// after
if err != nil {
    if strings.Contains(err.Error(), "message isn't an alive message") {
        logger.Warnf("discovery peer returned non-alive membership payload; retrying other peer")
    }
    return nil, err
}
peers, err := resp.ForChannel("mychannel")
Defensive patterns

Strategy: validation

Validate before calling

func aliveMsgLooksValid(m *gprotoext.SignedGossipMessage) error {
    if m == nil || m.GetAliveMsg() == nil { return errors.New("not an alive message") }
    if m.GetAliveMsg().Membership == nil { return errors.New("membership is empty") }
    if m.GetAliveMsg().Timestamp == nil { return errors.New("timestamp is nil") }
    return nil
}

Type guard

func isAliveMsg(m *gprotoext.SignedGossipMessage) bool { return m != nil && m.GetAliveMsg() != nil }

Try / catch

if err != nil && strings.Contains(err.Error(), "message isn't an alive message") {
    logger.Warnf("discovery peer returned non-membership payload; selecting alternate peer")
    return fallbackDiscovery(ctx)
}

Prevention

When it happens

Trigger: A discovery response (from peersForChannel or the endorser flow) contains a peer record whose gossip message is a StateInfo, DataMsg, or empty payload instead of an AliveMsg.

Common situations: Peer gossip store corrupted or out of sync; querying a peer before it joined the channel; Fabric version mismatch where membership payloads differ; a peer returning internal state messages instead of membership snapshots.

Related errors


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