hyperledger/fabric · error
bad type
Error message
bad type
What it means
ValidateUpdateConfigEnvelope only accepts envelopes whose ChannelHeader type is HeaderType_CONFIG_UPDATE. This error means the envelope is valid protobuf but of the wrong message type (e.g. ENDORSER_TRANSACTION, MESSAGE, CONFIG).
Source
Thrown at orderer/common/channelparticipation/validator.go:89
// It verifies it is an application channel by checking that the application group exists.
// It returns an error when it cannot be used as a update config envelope.
func ValidateUpdateConfigEnvelope(env *cb.Envelope) (channelID string, err error) {
payload, err := protoutil.UnmarshalPayload(env.Payload)
if err != nil {
return "", errors.New("bad payload")
}
if payload.Header == nil || payload.Header.ChannelHeader == nil {
return "", errors.New("bad header")
}
ch, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return "", errors.New("could not unmarshall channel header")
}
if ch.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
return "", errors.New("bad type")
}
if ch.ChannelId == "" {
return "", errors.New("empty channel id")
}
configUpdateEnv, err := protoutil.EnvelopeToConfigUpdate(env)
if err != nil {
return "", err
}
configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate)
if err != nil {
return "", err
}
return configUpdate.ChannelId, nil
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Extract the ConfigUpdateEnvelope from the config block: read the block's CONFIG envelope and take its ConfigUpdate field, then wrap it as HeaderType_CONFIG_UPDATE.
- Use configtxlator (proto_decode / proto_encode between common.Config and ConfigUpdate) to build the correct envelope type.
- Check ch.Type before submitting: it must equal int32(cb.HeaderType_CONFIG_UPDATE) (value 2).
- Use the standard 'peer channel fetch config' + configtxlator + 'peer channel update' pipeline rather than raw block uploads.
Example fix
// before env = configBlockEnv // header type CONFIG, not CONFIG_UPDATE // after cuEnv, _ := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG_UPDATE, "mychannel", signer, configUpdate, 0, 0)
Defensive patterns
Strategy: validation
Validate before calling
hdr, _ := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if hdr.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
return fmt.Errorf("expected CONFIG_UPDATE envelope, got type %d", hdr.Type)
} Type guard
func isConfigUpdateEnvelope(env *cb.Envelope) bool {
p, err := protoutil.UnmarshalPayload(env.Payload)
if err != nil || p.Header == nil || p.Header.ChannelHeader == nil { return false }
ch, err := protoutil.UnmarshalChannelHeader(p.Header.ChannelHeader)
return err == nil && ch.Type == int32(cb.HeaderType_CONFIG_UPDATE)
} Try / catch
if _, err := ValidateUpdateConfigEnvelope(env); err != nil && strings.Contains(err.Error(), "bad type") {
// rebuild via protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG_UPDATE, ...)
} Prevention
- Distinguish CONFIG vs CONFIG_UPDATE envelope types; never upload raw config blocks as updates
- Use the configtxlator-based update pipeline (fetch config -> compute delta -> sign -> update)
- Check the header type in tooling before any participation API call
When it happens
Trigger: Submitting a regular transaction envelope, a CONFIG envelope, or any non-CONFIG_UPDATE envelope to the channel participation join/update API.
Common situations: Confusing a config-update envelope with a full CONFIG envelope; accidentally uploading a computed config block instead of a ConfigUpdateEnvelope; script reusing a transaction envelope from a ledger fetch.
Related errors
- error computing config update
- cannot enable channel capabilities without orderer support f
- Must set some OrdererAddresses
- failed computing orderer addresses
- orderer is required, but no ordering endpoint or endorser cl
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/dbdaf89b699941f3.
Report an issue: GitHub.