hyperledger/fabric · error
envelope unmarshalling failed
Error message
envelope unmarshalling failed
What it means
MaintenanceFilter.Apply wraps any failure to decode the incoming message as a CONFIG-type envelope (via protoutil.UnmarshalEnvelopeOfType) with this message. It means the envelope's payload could not be unmarshalled into a cb.ConfigEnvelope, or the envelope's header type/channel did not match HeaderType_CONFIG. The config transaction is therefore rejected before any migration-rule inspection occurs.
Source
Thrown at orderer/common/msgprocessor/maintenancefilter.go:64
support: support,
permittedTargetConsensusTypes: make(map[string]bool),
bccsp: bccsp,
}
mf.permittedTargetConsensusTypes["BFT"] = true
return mf
}
// Apply applies the maintenance filter on a CONFIG tx.
func (mf *MaintenanceFilter) Apply(message *cb.Envelope) error {
ordererConf, ok := mf.support.OrdererConfig()
if !ok {
logger.Panic("Programming error: orderer config not found")
}
configEnvelope := &cb.ConfigEnvelope{}
chanHdr, err := protoutil.UnmarshalEnvelopeOfType(message, cb.HeaderType_CONFIG, configEnvelope)
if err != nil {
return errors.Wrap(err, "envelope unmarshalling failed")
}
logger.Debugw("Going to inspect maintenance mode transition rules",
"ConsensusState", ordererConf.ConsensusState(), "channel", chanHdr.ChannelId)
err = mf.inspect(configEnvelope, ordererConf)
if err != nil {
return errors.Wrap(err, "config transaction inspection failed")
}
return nil
}
// inspect checks whether the next orderer config, extracted from the incoming configEnvelope, respects the
// transition rules of consensus-type migration using maintenance-mode.
func (mf *MaintenanceFilter) inspect(configEnvelope *cb.ConfigEnvelope, ordererConfig channelconfig.Orderer) error {
if configEnvelope.LastUpdate == nil {
return errors.Errorf("updated config does not include a config update")
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Verify the client constructs the envelope with protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, channelID, signer, configEnv, 0, 0)
- Check that the payload bytes are a marshalled cb.ConfigEnvelope, not a cb.ConfigUpdateEnvelope (which is only for the prepare/config-update step)
- Re-serialize with the same protobuf library generation used by the orderer (protos-go-apiv2 / protobuf-go)
- Inspect the wrapped cause via errors.Cause to see whether it is a header-type mismatch or a proto parse error
Example fix
// before: submitting a ConfigUpdateEnvelope directly as a CONFIG tx
env := protoutil.MarshalOrPanic(configUpdateEnv)
// after: wrap the config update into a full ConfigEnvelope and create a proper CONFIG envelope
configEnv := &cb.ConfigEnvelope{Config: nextConfig, LastUpdate: configUpdateEnv}
signedEnv, err := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, chID, signer, configEnv, 0, 0) Defensive patterns
Strategy: validation
Validate before calling
hdr := &cb.ChannelHeader{}
if err := proto.Unmarshal(env.Payload, &payload); err != nil { return err }
if err := proto.Unmarshal(payload.Header.ChannelHeader, hdr); err != nil { return err }
if hdr.Type != int32(cb.HeaderType_CONFIG) { return fmt.Errorf("not a CONFIG tx") }
ce := &cb.ConfigEnvelope{}
if err := proto.Unmarshal(payload.Data, ce); err != nil { return err }
if ce.LastUpdate == nil { return errors.New("LastUpdate missing") } Type guard
func isConfigEnvelope(env *cb.Envelope) bool {
p := &cb.Payload{}
if proto.Unmarshal(env.GetPayload(), p) != nil || p.GetHeader() == nil { return false }
return p.Header.ChannelHeader != nil && proto.Unmarshal(p.Header.ChannelHeader, &cb.ChannelHeader{}) == nil
} Try / catch
if err := filter.Apply(env); err != nil {
if strings.Contains(err.Error(), "envelope unmarshalling failed") {
log.Errorf("malformed CONFIG envelope: %v", errors.Cause(err))
return ErrBadEnvelope
}
return err
} Prevention
- Always build CONFIG envelopes with protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, ...)
- Never submit a ConfigUpdateEnvelope where a ConfigEnvelope is required
- Keep fabric-protos-go-apiv2 versions in sync between client and orderer
- Decode-and-recheck with configtxlator before submitting generated envelopes
When it happens
Trigger: A transaction with HeaderType_CONFIG reaches Apply but its payload is not a valid serialized ConfigEnvelope (corrupted, truncated, wrong proto encoding, or the header claims CONFIG while the payload is a different message type).
Common situations: A client or tooling script submits a malformed config envelope to the ordering service; a proxy/middleware re-encodes the envelope incorrectly; a fabric version upgrade changes proto serialization (gogo vs protobuf-go apiv2) and old bytes no longer parse.
Related errors
- data unmarshalling error: %s
- config must contain a channel group
- no header was set
- no channel header was set
- channel header unmarshalling error: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/77030c4011150611.
Report an issue: GitHub.