hyperledger/fabric · error
epoch is non-zero
Error message
epoch is non-zero
What it means
The endorser requires the proposal's ChannelHeader.Epoch to be zero. Epoch is reserved for future reconfiguration semantics in Fabric and non-zero values are rejected to prevent replay/reconfiguration confusion. Any proposal carrying a non-zero epoch is invalid.
Source
Thrown at core/endorser/msgvalidation.go:143
ChannelID: up.ChannelHeader.ChannelId,
TxID: up.TxID(),
})
// validate the header type
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 {View on GitHub (pinned to 2736b63f8f)
Solutions
- Leave ChannelHeader.Epoch as 0 (do not set it) when constructing proposals.
- If copying headers from other messages, explicitly zero the Epoch field.
- Use a supported Fabric SDK to construct proposals rather than hand-writing channel headers.
Example fix
// before
chdr := &common.ChannelHeader{Type: 1, TxId: txid, Epoch: 5}
// after
chdr := &common.ChannelHeader{Type: 1, TxId: txid, Epoch: 0} Defensive patterns
Strategy: validation
Validate before calling
if hdr.Epoch != 0 {
return errors.New("epoch must be 0 for endorsement proposals")
} Type guard
func hasZeroEpoch(h *common.ChannelHeader) bool {
return h != nil && h.Epoch == 0
} Prevention
- Never set ChannelHeader.Epoch manually
- Zero all header fields you don't understand when copying headers
- Use SDK builders instead of hand-written headers
When it happens
Trigger: ProcessProposal -> preProcess -> Validate on a SignedProposal where up.ChannelHeader.Epoch != 0 — usually a manually built channel header with Epoch set from another system (e.g. Kafka epoch, view number).
Common situations: Custom client code that fills ChannelHeader fields generically and sets Epoch, ported code from other blockchain SDKs where 'epoch' means something else, mutated/replayed messages.
Related errors
- invalid header type %s
- chaincode invocation spec did not contain chaincode spec
- chaincode input did not contain any input
- nonce is empty
- creator is empty
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/191631fc7cc10ea5.
Report an issue: GitHub.