hyperledger/fabric · error
ConfigEnvelope LastUpdate did not produce the supplied confi
Error message
ConfigEnvelope LastUpdate did not produce the supplied config result
What it means
After converting LastUpdate back to a channelGroup, Validate checks that the reconstructed group exactly equals the ChannelGroup supplied in the ConfigEnvelope (using proto.Equal). If they differ, the envelope is internally inconsistent — the claimed final config doesn't match what the update produces.
Source
Thrown at common/configtx/validator.go:192
configUpdateEnv, err := protoutil.EnvelopeToConfigUpdate(configEnv.LastUpdate)
if err != nil {
return err
}
configMap, err := vi.authorizeUpdate(configUpdateEnv)
if err != nil {
return err
}
channelGroup, err := configMapToConfig(configMap, vi.namespace)
if err != nil {
return errors.Errorf("could not turn configMap back to channelGroup: %s", err)
}
// reflect.Equal will not work here, because it considers nil and empty maps as different
if !proto.Equal(channelGroup, configEnv.Config.ChannelGroup) {
return errors.Errorf("ConfigEnvelope LastUpdate did not produce the supplied config result")
}
return nil
}
// ChannelID retrieves the channel ID associated with this manager
func (vi *ValidatorImpl) ChannelID() string {
return vi.channelID
}
// Sequence returns the sequence number of the config
func (vi *ValidatorImpl) Sequence() uint64 {
return vi.sequence
}
// ConfigProto returns the config proto which initialized this Validator
func (vi *ValidatorImpl) ConfigProto() *cb.Config {
return vi.configProtoView on GitHub (pinned to 2736b63f8f)
Solutions
- Recompute LastUpdate (computeDeltaConfigUpdate) from the current config and the desired final config so both parts agree
- Regenerate the whole envelope with configtxlator's 'update' output instead of hand-editing ChannelGroup
- Compare ChannelGroup and the reconstructed group to find the differing field
- Use configtxgen to build the update from the same source profile used for the config
Example fix
// before env.Config.ChannelGroup = editedGroup // LastUpdate stale // after update := computeDeltaConfigUpdate(currentConfig, editedGroup) env.LastUpdate = wrapConfigUpdate(update) env.Config.ChannelGroup = editedGroup
Defensive patterns
Strategy: validation
Validate before calling
// ensure update result matches the claimed final config before submit
recomputed, err := configMapToConfig(configMap, namespace)
if err != nil || !proto.Equal(recomputed, env.Config.ChannelGroup) {
return errors.New("recompute LastUpdate from current+desired config")
} Try / catch
if err := validator.Validate(env, fullPayload); err != nil {
if strings.Contains(err.Error(), "did not produce the supplied config result") {
env = recomputeEnvelope(currentConfig, desiredConfig) // rebuild both parts together
}
} Prevention
- Never edit Config.ChannelGroup without recomputing LastUpdate
- Always build both ChannelGroup and LastUpdate from the same source profile
- Round-trip the envelope through configtxlator to verify consistency before submission
When it happens
Trigger: Submitting a ConfigEnvelope where Config.ChannelGroup was edited independently of LastUpdate — e.g. manually patching the full config but leaving a stale/different update transaction inside.
Common situations: Manually editing config via configtxlator then forgetting to recompute LastUpdate; tools that generate the full config but copy an old update blob; merging updates from different sources.
Related errors
- Attempted to set the batch size max message count to an inva
- Attempted to set the batch size absolute max bytes to an inv
- Attempted to set the batch size preferred max bytes to an in
- Attempted to set the batch size preferred max bytes (%v) gre
- Attempted to set the batch timeout to a invalid value: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/3669c18ab050ec9b.
Report an issue: GitHub.