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

  1. Set ChannelHeader.Epoch to 0 when constructing transactions
  2. Update the client/SDK code to stop copying epoch values from channel config into the header
  3. If you believe epoch enforcement is the problem, verify all parties build headers consistently with Epoch=0
  4. 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

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


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