{"record":{"id":"3669c18ab050ec9b","repo":"hyperledger/fabric","slug":"configenvelope-lastupdate-did-not-produce-the-supp","errorCode":null,"errorMessage":"ConfigEnvelope LastUpdate did not produce the supplied config result","messagePattern":"ConfigEnvelope LastUpdate did not produce the supplied config result","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/configtx/validator.go","lineNumber":192,"sourceCode":"\n\tconfigUpdateEnv, err := protoutil.EnvelopeToConfigUpdate(configEnv.LastUpdate)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconfigMap, err := vi.authorizeUpdate(configUpdateEnv)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tchannelGroup, err := configMapToConfig(configMap, vi.namespace)\n\tif err != nil {\n\t\treturn errors.Errorf(\"could not turn configMap back to channelGroup: %s\", err)\n\t}\n\n\t// reflect.Equal will not work here, because it considers nil and empty maps as different\n\tif !proto.Equal(channelGroup, configEnv.Config.ChannelGroup) {\n\t\treturn errors.Errorf(\"ConfigEnvelope LastUpdate did not produce the supplied config result\")\n\t}\n\n\treturn nil\n}\n\n// ChannelID retrieves the channel ID associated with this manager\nfunc (vi *ValidatorImpl) ChannelID() string {\n\treturn vi.channelID\n}\n\n// Sequence returns the sequence number of the config\nfunc (vi *ValidatorImpl) Sequence() uint64 {\n\treturn vi.sequence\n}\n\n// ConfigProto returns the config proto which initialized this Validator\nfunc (vi *ValidatorImpl) ConfigProto() *cb.Config {\n\treturn vi.configProto","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/configtx/validator.go#L174-L210","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nenv.Config.ChannelGroup = editedGroup // LastUpdate stale\n// after\nupdate := computeDeltaConfigUpdate(currentConfig, editedGroup)\nenv.LastUpdate = wrapConfigUpdate(update)\nenv.Config.ChannelGroup = editedGroup","handlingStrategy":"validation","validationCode":"// ensure update result matches the claimed final config before submit\nrecomputed, err := configMapToConfig(configMap, namespace)\nif err != nil || !proto.Equal(recomputed, env.Config.ChannelGroup) {\n    return errors.New(\"recompute LastUpdate from current+desired config\")\n}","typeGuard":null,"tryCatchPattern":"if err := validator.Validate(env, fullPayload); err != nil {\n    if strings.Contains(err.Error(), \"did not produce the supplied config result\") {\n        env = recomputeEnvelope(currentConfig, desiredConfig) // rebuild both parts together\n    }\n}","preventionTips":["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"],"tags":["hyperledger-fabric","configtx","consistency"],"backgroundTag":"config-update-result-mismatch","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}