hyperledger/fabric · error

Invalid Block on channel [%s]. Block is nil.

Error message

Invalid Block on channel [%s]. Block is nil.

What it means

VerifyBlockAttestation was called with a nil *common.Block. The method validates the block pointer before touching any fields and returns this error immediately. It is a caller-side input error: no attestation can be verified for a nonexistent block.

Source

Thrown at internal/peer/gossip/mcs.go:200

	var consenters []*pcommon.Consenter
	if bftEnabled {
		cfg, ok := chConfig.OrdererConfig()
		if !ok {
			return fmt.Errorf("no orderer section in channel config for channel [%s].", channelID)
		}
		consenters = cfg.Consenters()
	}

	verifier := protoutil.BlockSignatureVerifier(bftEnabled, consenters, policy)
	return verifier(block.Header, block.Metadata)
}

// VerifyBlockAttestation returns nil when the header matches the metadata signature. It assumed the block.Data is nil
// and therefore does not verify that Header.DataHash is equal to the hash of block.Data. This is used when the orderer
// delivers a block with header & metadata only, as an attestation of block existence.
func (s *MSPMessageCryptoService) VerifyBlockAttestation(chainID string, block *pcommon.Block) error {
	if block == nil {
		return fmt.Errorf("Invalid Block on channel [%s]. Block is nil.", chainID)
	}
	if block.Header == nil {
		return fmt.Errorf("Invalid Block on channel [%s]. Header must be different from nil.", chainID)
	}

	// - Unmarshal medatada
	if block.Metadata == nil || len(block.Metadata.Metadata) == 0 {
		return fmt.Errorf("Block with id [%d] on channel [%s] does not have metadata. Block not valid.", block.Header.Number, chainID)
	}

	return s.verifyHeaderAndMetadata(chainID, block)
}

// Sign signs msg with this peer's signing key and outputs
// the signature if no error occurred.
func (s *MSPMessageCryptoService) Sign(msg []byte) ([]byte, error) {
	return s.localSigner.Sign(msg)
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Add a nil check on the block before calling VerifyBlockAttestation.
  2. Trace where the block originates (orderer delivery or gossip) and fix the nil propagation at the source.
  3. If the block came from unmarshaling, check that Unmarshal error was handled before use.
  4. Log the channel and caller stack to find which producer supplied the nil block.

Example fix

// before
cryptoService.VerifyBlockAttestation(chainID, block)
// after
if block == nil {
    return fmt.Errorf("refusing attestation check: nil block on channel %s", chainID)
}
cryptoService.VerifyBlockAttestation(chainID, block)
Defensive patterns

Strategy: type-guard

Validate before calling

if block == nil {
    return fmt.Errorf("nil block cannot be attested on channel %s", chainID)
}

Type guard

func isAttestableBlock(b *common.Block) bool {
    return b != nil && b.Header != nil && b.Metadata != nil && len(b.Metadata.Metadata) > 0
}

Try / catch

if err := cryptoService.VerifyBlockAttestation(chainID, block); err != nil {
    if strings.Contains(err.Error(), "Block is nil") {
        log.Warnf("skipping attestation: nil block supplied on %s", chainID)
        return errSkip
    }
    return err
}

Prevention

When it happens

Trigger: Any invocation of MSPMessageCryptoService.VerifyBlockAttestation(chainID, block) where the block argument is nil — e.g., a gossip callback or delivery handler passing a block that failed to be assigned/parsed upstream.

Common situations: Gossip/delivery code paths that propagate nil blocks after failed unmarshaling; callers skipping nil checks on blocks pulled from queues or channels; test harnesses invoking attestation with uninitialized fixtures.

Related errors


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