hyperledger/fabric · error
no signatures in block metadata
Error message
no signatures in block metadata
What it means
BlockSignatureVerifier validates a block's signature metadata. If the block metadata slice does not contain an entry at BlockMetadataIndex_SIGNATURES (metadata too short), there are no signatures to verify, so it fails with this error. It guards against accepting unsigned or structurally invalid blocks.
Source
Thrown at protoutil/blockutils.go:254
}
}
type VerifierBuilder func(block *cb.Block) BlockVerifierFunc
type BlockVerifierFunc func(header *cb.BlockHeader, metadata *cb.BlockMetadata) error
//go:generate counterfeiter -o mocks/policy.go --fake-name Policy . policy
type policy interface { // copied from common.policies to avoid circular import.
// EvaluateSignedData takes a set of SignedData and evaluates whether
// 1) the signatures are valid over the related message
// 2) the signing identities satisfy the policy
EvaluateSignedData(signatureSet []*SignedData) error
}
func BlockSignatureVerifier(bftEnabled bool, consenters []*cb.Consenter, policy policy) BlockVerifierFunc {
return func(header *cb.BlockHeader, metadata *cb.BlockMetadata) error {
if len(metadata.GetMetadata()) < int(cb.BlockMetadataIndex_SIGNATURES)+1 {
return errors.Errorf("no signatures in block metadata")
}
md := &cb.Metadata{}
if err := proto.Unmarshal(metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES], md); err != nil {
return errors.Wrapf(err, "error unmarshalling signatures from metadata: %v", err)
}
var signatureSet []*SignedData
for _, metadataSignature := range md.Signatures {
var signerIdentity []byte
var signedPayload []byte
// if the SignatureHeader is empty and the IdentifierHeader is present, then the consenter expects us to fetch its identity by its numeric identifier
if bftEnabled && len(metadataSignature.GetSignatureHeader()) == 0 && len(metadataSignature.GetIdentifierHeader()) > 0 {
identifierHeader, err := UnmarshalIdentifierHeader(metadataSignature.IdentifierHeader)
if err != nil {
return fmt.Errorf("failed unmarshalling identifier header for block %d: %v", header.GetNumber(), err)
}
identifier := identifierHeader.GetIdentifier()View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure blocks come from a legitimate ordering service that always writes the SIGNATURES metadata entry
- Check block.Metadata length before invoking the verifier and reject early with a clearer message
- If building test blocks, populate Metadata[BlockMetadataIndex_SIGNATURES] with a signed cb.Metadata
- Confirm BFT/standard ordering metadata index layout matches the verifier configuration (bftEnabled flag)
Example fix
// before
err := verifier(header, metadata)
// after
if len(metadata.GetMetadata()) < int(cb.BlockMetadataIndex_SIGNATURES)+1 {
return errors.Errorf("block %d: metadata has no SIGNATURES entry", header.GetNumber())
}
err := verifier(header, metadata) Defensive patterns
Strategy: validation
Validate before calling
func hasSignatureEntry(metadata *cb.BlockMetadata) bool {
return len(metadata.GetMetadata()) >= int(cb.BlockMetadataIndex_SIGNATURES)+1
}
if !hasSignatureEntry(md) {
return errors.New("block lacks signature metadata; reject")
} Type guard
func isSignedBlock(block *cb.Block) bool {
return len(block.GetMetadata().GetMetadata()) >= int(cb.BlockMetadataIndex_SIGNATURES)+1
} Try / catch
if err := verifier(header, metadata); err != nil {
return fmt.Errorf("rejecting block %d: %w", header.GetNumber(), err)
} Prevention
- Only accept blocks from authorized ordering nodes
- Never bypass block verification even for genesis-like blocks in tests — build signed metadata instead
- Check metadata array length before verification
- Ensure bftEnabled matches the channel's actual consensus type
When it happens
Trigger: Calling the returned BlockVerifierFunc with a cb.BlockMetadata whose Metadata array has fewer entries than BlockMetadataIndex_SIGNATURES+1 — e.g. a genesis-like block, a hand-crafted block, or truncated metadata.
Common situations: Delivering blocks from an untrusted/misbehaving ordering node, testing with manually constructed blocks lacking signatures, or version mismatch where signature metadata is stored at a different index.
Related errors
- error unmarshalling signatures from metadata: %v
- last block header hash is missing
- failed to verify transactions are well formed for block with
- Header.DataHash is different from Hash(block.Data) for block
- block with id [%d] on channel [%s] does not have metadata or
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/2e4c988e4f8efbb0.
Report an issue: GitHub.