hyperledger/fabric · error
nonce is empty
Error message
nonce is empty
What it means
Every endorsement proposal must carry a nonce in its SignatureHeader; the nonce is a random value combined with the creator to form a unique transaction ID and prevent replay. An empty nonce makes the proposal invalid.
Source
Thrown at core/endorser/msgvalidation.go:148
switch common.HeaderType(up.ChannelHeader.Type) {
case common.HeaderType_ENDORSER_TRANSACTION:
case common.HeaderType_CONFIG:
// The CONFIG transaction type has _no_ business coming to the propose API.
// In fact, anything coming to the Propose API is by definition an endorser
// transaction, so any other header type seems like it ought to be an error... oh well.
default:
return errors.Errorf("invalid header type %s", common.HeaderType(up.ChannelHeader.Type))
}
// ensure the epoch is 0
if up.ChannelHeader.Epoch != 0 {
return errors.Errorf("epoch is non-zero")
}
// ensure that there is a nonce
if len(up.SignatureHeader.Nonce) == 0 {
return errors.Errorf("nonce is empty")
}
// ensure that there is a creator
if len(up.SignatureHeader.Creator) == 0 {
return errors.New("creator is empty")
}
expectedTxID := protoutil.ComputeTxID(up.SignatureHeader.Nonce, up.SignatureHeader.Creator)
if up.TxID() != expectedTxID {
return errors.Errorf("incorrectly computed txid '%s' -- expected '%s'", up.TxID(), expectedTxID)
}
if up.SignedProposal.ProposalBytes == nil {
return errors.Errorf("empty proposal bytes")
}
if up.SignedProposal.Signature == nil {
return errors.Errorf("empty signature bytes")View on GitHub (pinned to 2736b63f8f)
Solutions
- Generate a cryptographically random nonce (e.g. 24 bytes from crypto/rand) and set it in the SignatureHeader before signing.
- Use SDK proposal helpers (newProposal / ChaincodeProposalFactory) which generate the nonce automatically.
- Verify the serialized SignatureHeader used for signing matches the one embedded in the proposal.
Example fix
// before
shdr := &common.SignatureHeader{Creator: creator}
// after
nonce := make([]byte, 24)
rand.Read(nonce)
shdr := &common.SignatureHeader{Creator: creator, Nonce: nonce} Defensive patterns
Strategy: validation
Validate before calling
if len(shdr.Nonce) == 0 {
return errors.New("nonce required: generate 24 random bytes via crypto/rand")
} Type guard
func hasNonce(sh *common.SignatureHeader) bool {
return sh != nil && len(sh.Nonce) > 0
} Prevention
- Generate a fresh crypto/rand nonce per proposal
- Let the SDK generate nonce and TxID together
- Never rebuild a SignatureHeader from a deserialized proposal without preserving the nonce
When it happens
Trigger: ProcessProposal -> preProcess -> Validate on a SignedProposal whose SignatureHeader.Nonce is a zero-length byte slice — typically a manually assembled SignatureHeader without setting Nonce.
Common situations: Hand-rolled protobuf client code, test fixtures with empty signature headers, clients that deserialize a proposal and rebuild it dropping the nonce.
Related errors
- creator is empty
- nil SignatureHeader provided
- invalid nonce specified in the header
- invalid creator specified in the header
- chaincode invocation spec did not contain chaincode spec
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/2f66481fc5c5877f.
Report an issue: GitHub.