hyperledger/fabric · error
envelope must have a Header
Error message
envelope must have a Header
What it means
UnmarshalEnvelopeOfType unmarshals the envelope's Payload and then requires payload.Header to be present, since the channel header and signature header needed for type/channel validation live there. A payload without a Header cannot be routed or authenticated, so the function returns 'envelope must have a Header'.
Source
Thrown at protoutil/commonutils.go:66
return nonce
}
// CreateNonce generates a nonce using the common/crypto package.
func CreateNonce() ([]byte, error) {
nonce, err := getRandomNonce()
return nonce, errors.WithMessage(err, "error generating random nonce")
}
// UnmarshalEnvelopeOfType unmarshals an envelope of the specified type,
// including unmarshalling the payload data
func UnmarshalEnvelopeOfType(envelope *cb.Envelope, headerType cb.HeaderType, message proto.Message) (*cb.ChannelHeader, error) {
payload, err := UnmarshalPayload(envelope.Payload)
if err != nil {
return nil, err
}
if payload.Header == nil {
return nil, errors.New("envelope must have a Header")
}
chdr, err := UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return nil, err
}
if chdr.Type != int32(headerType) {
return nil, errors.Errorf("invalid type %s, expected %s", cb.HeaderType(chdr.Type), headerType)
}
err = proto.Unmarshal(payload.Data, message)
err = errors.Wrapf(err, "error unmarshalling message for type %s", headerType)
return chdr, err
}
// ExtractEnvelopeOrPanic retrieves the requested envelope from a given block
// and unmarshals it -- it panics if either of these operations failView on GitHub (pinned to 2736b63f8f)
Solutions
- Populate the payload header before marshaling: use protoutil.MakeChannelHeader and BuildHeader, and set payload.Header.ChannelHeader/SignatureHeader.
- Verify the client/proxy that creates the message actually attaches a header.
- Validate incoming envelopes early and reject those without headers with a clearer application-level error.
- If reading from a block, re-fetch from a trusted source — the payload may be corrupt.
Example fix
// before
payload := &cb.Payload{Data: data}
// after
chdr := protoutil.MakeChannelHeader(cb.HeaderType_ENDORSER_TRANSACTION, 0, channelID, 0)
payload := &cb.Payload{Header: protoutil.MakePayloadHeader(chdr, sighdr), Data: data} Defensive patterns
Strategy: validation
Validate before calling
env := &cb.Envelope{}
_ = proto.Unmarshal(raw, env)
payload := &cb.Payload{}
_ = proto.Unmarshal(env.Payload, payload)
if payload.Header == nil || len(payload.Header.ChannelHeader) == 0 {
return errors.New("payload must carry a Header with ChannelHeader")
} Type guard
func hasHeader(payload *cb.Payload) bool {
return payload != nil && payload.Header != nil && len(payload.Header.ChannelHeader) > 0
} Prevention
- Always build payloads with protoutil.MakePayloadHeader / BuildHeader.
- Validate envelopes (header present, type correct) at the ingress boundary.
- Never rebuild Payload structs manually in middleware.
- Include header-presence assertions in integration tests for message submission.
When it happens
Trigger: Calling UnmarshalEnvelopeOfType (directly or via ProcessConfigMsg, Apply, validateConfigBlock, extractChannelConfig) with an envelope whose inner payload.Header is nil — e.g. a payload built without SetHeader or a payload deserialized from tampered data.
Common situations: Submitting config/transaction messages constructed manually without a header; corrupted payloads read from storage; test envelopes missing &cb.Payload{Header: ...}; middleware that rebuilt the payload and dropped the header.
Related errors
- unmarshalling block: %s
- unmarshalling envelope: %s
- invalid chaincode event
- nil SignatureHeader provided
- nil ChannelHeader provided
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/a32de73068127b72.
Report an issue: GitHub.