{"record":{"id":"61ebf87683f677df","repo":"hyperledger/fabric","slug":"update-of-more-than-one-consenter-at-a-time-is-not","errorCode":null,"errorMessage":"update of more than one consenter at a time is not supported, requested changes: %s","messagePattern":"update of more than one consenter at a time is not supported, requested changes: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/membership.go","lineNumber":102,"sourceCode":"\t\tresult.NewBlockMetadata.ConsenterIds[addedNodeIndex] = nodeID\n\t\tresult.NewBlockMetadata.NextConsenterId++\n\t\tresult.ConfChange = &raftpb.ConfChange{\n\t\t\tNodeId: &nodeID,\n\t\t\tType:   new(raftpb.ConfChangeAddNode),\n\t\t}\n\tcase len(result.AddedNodes) == 0 && len(result.RemovedNodes) == 1:\n\t\t// removed node\n\t\tnodeID := deletedNodeID\n\t\tresult.ConfChange = &raftpb.ConfChange{\n\t\t\tNodeId: &nodeID,\n\t\t\tType:   new(raftpb.ConfChangeRemoveNode),\n\t\t}\n\t\tdelete(result.NewConsenters, nodeID)\n\tcase len(result.AddedNodes) == 0 && len(result.RemovedNodes) == 0:\n\t\t// no change\n\tdefault:\n\t\t// len(result.AddedNodes) > 1 || len(result.RemovedNodes) > 1 {\n\t\treturn nil, errors.Errorf(\"update of more than one consenter at a time is not supported, requested changes: %s\", result)\n\t}\n\n\treturn result, nil\n}\n\n// Stringer implements fmt.Stringer interface\nfunc (mc *MembershipChanges) String() string {\n\treturn fmt.Sprintf(\"add %d node(s), remove %d node(s)\", len(mc.AddedNodes), len(mc.RemovedNodes))\n}\n\n// Changed indicates whether these changes actually do anything\nfunc (mc *MembershipChanges) Changed() bool {\n\treturn len(mc.AddedNodes) > 0 || len(mc.RemovedNodes) > 0\n}\n\n// Rotated indicates whether the change was a rotation\nfunc (mc *MembershipChanges) Rotated() bool {\n\treturn len(mc.AddedNodes) == 1 && len(mc.RemovedNodes) == 1","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/membership.go#L84-L120","documentation":"ComputeMembershipChanges guard: the proposed consenter set differs from the current one by more than one node (multiple added and/or removed in a single change). Raft configuration changes must be applied one consenter at a time; the requested changes are listed in the message.","triggerScenarios":"Thrown at orderer/consensus/etcdraft/membership.go:102 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Split the configuration update into separate config transactions, one consenter change each","Use a tool (e.g. fabric-tools reconfig) that serializes consenter additions/removals"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}