hyperledger/fabric · error

block from orderer could not be re-marshaled: proto: Marshal

Error message

block from orderer could not be re-marshaled: proto: Marshal called with nil

What it means

GossipBlockHandler.HandleBlock returns this fixed-message error when the block received from the orderer is nil, before attempting proto.Marshal. The message text mirrors the proto error that marshaling a nil message would produce ('proto: Marshal called with nil'), so callers can treat it uniformly. It signals the orderer/gossip path handed the handler an invalid block.

Source

Thrown at core/deliverservice/gossip_block_handler.go:37

//
//go:generate counterfeiter -o fake/gossip_service_adapter.go --fake-name GossipServiceAdapter . GossipServiceAdapter
type GossipServiceAdapter interface {
	// AddPayload adds payload to the local state sync buffer
	AddPayload(chainID string, payload *gossip.Payload) error

	// Gossip the message across the peers
	Gossip(msg *gossip.GossipMessage)
}

type GossipBlockHandler struct {
	gossip              GossipServiceAdapter
	blockGossipDisabled bool
	logger              *flogging.FabricLogger
}

func (h *GossipBlockHandler) HandleBlock(channelID string, block *common.Block) error {
	if block == nil {
		return errors.New("block from orderer could not be re-marshaled: proto: Marshal called with nil")
	}
	marshaledBlock, err := proto.Marshal(block)
	if err != nil {
		return errors.WithMessage(err, "block from orderer could not be re-marshaled")
	}

	// Create payload with a block received
	blockNum := block.GetHeader().GetNumber()
	payload := &gossip.Payload{
		Data:   marshaledBlock,
		SeqNum: blockNum,
	}

	// Use payload to create gossip message
	gossipMsg := &gossip.GossipMessage{
		Nonce:   0,
		Tag:     gossip.GossipMessage_CHAN_AND_ORG,
		Channel: []byte(channelID),

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Fix the upstream producer so it never invokes HandleBlock with a nil block; add a nil check before calling it
  2. Log and drop the nil block on the caller side, resyncing blocks via the normal delivery stream
  3. Upgrade orderer/peer to matching versions to rule out serialization bugs
  4. If persistent, capture orderer logs and file an issue; restart the delivery service to re-establish the block stream

Example fix

// before
handler.HandleBlock(channelID, blockFromOrderer) // block may be nil
// after
if blockFromOrderer == nil {
    logger.Warningf("skipping nil block for channel %s", channelID)
    return
}
handler.HandleBlock(channelID, blockFromOrderer)
Defensive patterns

Strategy: type-guard

Validate before calling

if block == nil || block.Header == nil {
    logger.Warningf("invalid block from orderer for channel %s", channelID)
    return
}
HandleBlock(channelID, block)

Type guard

func isValidBlock(b *common.Block) bool {
    return b != nil && b.Header != nil && b.Data != nil
}

Try / catch

if err := handler.HandleBlock(channelID, blk); err != nil {
    if strings.Contains(err.Error(), "could not be re-marshaled") {
        logger.Errorf("dropping invalid block on %s: %v", channelID, err)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: HandleBlock(channelID, block) is invoked with block == nil, e.g. a nil block propagated from the deliver client or gossip pipeline.

Common situations: Orderer disconnects or upstream bugs yielding nil blocks; version mismatches between orderer and peer; corrupted internal state in the block delivery pipeline; tests invoking HandleBlock with nil to simulate bad input.

Related errors


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