hyperledger/fabric · error
invalid Epoch in ChannelHeader. Expected 0, got [%d]
Error message
invalid Epoch in ChannelHeader. Expected 0, got [%d]
What it means
validateChannelHeader currently enforces that ChannelHeader.Epoch is 0, since epoch management is not yet in place. If a transaction carries a non-zero Epoch it is rejected with this error reporting the received value.
Source
Thrown at core/common/validation/msgvalidation.go:111
// validate the header type
switch common.HeaderType(cHdr.Type) {
case common.HeaderType_ENDORSER_TRANSACTION:
case common.HeaderType_CONFIG_UPDATE:
case common.HeaderType_CONFIG:
default:
return errors.Errorf("invalid header type %s", common.HeaderType(cHdr.Type))
}
putilsLogger.Debugf("validateChannelHeader info: header type %d", common.HeaderType(cHdr.Type))
// TODO: validate channelID in cHdr.ChannelID
// Validate epoch in cHdr.Epoch
// Currently we enforce that Epoch is 0.
// TODO: This check will be modified once the Epoch management
// will be in place.
if cHdr.Epoch != 0 {
return errors.Errorf("invalid Epoch in ChannelHeader. Expected 0, got [%d]", cHdr.Epoch)
}
// TODO: Validate version in cHdr.Version
return nil
}
// checks for a valid Header
func validateCommonHeader(hdr *common.Header) (*common.ChannelHeader, *common.SignatureHeader, error) {
if hdr == nil {
return nil, nil, errors.New("nil header")
}
chdr, err := protoutil.UnmarshalChannelHeader(hdr.ChannelHeader)
if err != nil {
return nil, nil, err
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Set ChannelHeader.Epoch to 0 when constructing transactions
- Update the client/SDK code to stop copying epoch values from channel config into the header
- If you believe epoch enforcement is the problem, verify all parties build headers consistently with Epoch=0
- Check Fabric version notes: until epoch management lands, 0 is the only accepted value
Example fix
// before
chdr := &common.ChannelHeader{Type: int32(common.HeaderType_ENDORSER_TRANSACTION), ChannelId: channelID, Epoch: epochFromConfig}
// after
chdr := &common.ChannelHeader{Type: int32(common.HeaderType_ENDORSER_TRANSACTION), ChannelId: channelID, Epoch: 0} Defensive patterns
Strategy: validation
Validate before calling
func epochIsZero(chdr *common.ChannelHeader) bool {
return chdr != nil && chdr.Epoch == 0
} Try / catch
if err != nil && strings.HasPrefix(err.Error(), "invalid Epoch in ChannelHeader") {
// set Epoch to 0 in the ChannelHeader and re-sign the payload
} Prevention
- Hardcode Epoch: 0 in all transaction-header builders until epoch management ships
- Do not copy epoch values from channel config metadata into transaction headers
- Add a header-construction unit test asserting Epoch == 0
When it happens
Trigger: Submitting an envelope whose ChannelHeader.Epoch is set to any non-zero value — e.g. a client copying epoch values from config metadata, or hand-building headers with a hardcoded non-zero epoch.
Common situations: Custom clients attempting to implement epoch semantics that Fabric does not yet support; fixtures ported from other Fabric components where epoch is populated; SDK versions that set epoch from channel config views.
Related errors
- nil ChannelHeader provided
- invalid epoch in ChannelHeader. Expected 0, got [%d]
- invalid version in ChannelHeader. Expected 0, got [%d]
- '%s' not equal <newest|oldest|config|(number)>
- unmarshalling block: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/75b04479865fe343.
Report an issue: GitHub.