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

  1. Verify the client constructs the envelope with protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, channelID, signer, configEnv, 0, 0)
  2. Check that the payload bytes are a marshalled cb.ConfigEnvelope, not a cb.ConfigUpdateEnvelope (which is only for the prepare/config-update step)
  3. Re-serialize with the same protobuf library generation used by the orderer (protos-go-apiv2 / protobuf-go)
  4. 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

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


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