{"record":{"id":"2de631eba7d9501f","repo":"hyperledger/fabric","slug":"orderer-org-s-attempted-to-change-msp-id-from-s","errorCode":null,"errorMessage":"orderer org %s attempted to change MSP ID from %s to %s","messagePattern":"orderer org (.+?) attempted to change MSP ID from (.+?) to (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/channelconfig/bundle.go","lineNumber":114,"sourceCode":"\t\t// When we move to capability V3_0 we insist on per Org endpoints for every org\n\t\tisOldV3 := b.ChannelConfig().Capabilities().ConsensusTypeBFT()\n\t\tisNewV3 := nb.ChannelConfig().Capabilities().ConsensusTypeBFT()\n\t\tif !isOldV3 && isNewV3 {\n\t\t\tfor _, org := range noc.Organizations() {\n\t\t\t\tif len(org.Endpoints()) == 0 {\n\t\t\t\t\treturn errors.Errorf(\"illegal orderer config update detected: endpoints of org %s are missing\", org.Name())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor orgName, org := range oc.Organizations() {\n\t\t\tnorg, ok := noc.Organizations()[orgName]\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmspID := org.MSPID()\n\t\t\tif mspID != norg.MSPID() {\n\t\t\t\treturn errors.Errorf(\"orderer org %s attempted to change MSP ID from %s to %s\", orgName, mspID, norg.MSPID())\n\t\t\t}\n\t\t}\n\t}\n\n\tif ac, ok := b.ApplicationConfig(); ok {\n\t\tnac, ok := nb.ApplicationConfig()\n\t\tif !ok {\n\t\t\treturn errors.New(\"current config has application section, but new config does not\")\n\t\t}\n\n\t\tfor orgName, org := range ac.Organizations() {\n\t\t\tnorg, ok := nac.Organizations()[orgName]\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmspID := org.MSPID()\n\t\t\tif mspID != norg.MSPID() {\n\t\t\t\treturn errors.Errorf(\"application org %s attempted to change MSP ID from %s to %s\", orgName, mspID, norg.MSPID())","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/channelconfig/bundle.go#L96-L132","documentation":"ValidateNew in Hyperledger Fabric's channelconfig enforces that the MSP ID of an existing orderer organization can never be changed via a channel config update. When iterating old vs new orderer orgs, if org.MSPID() differs from norg.MSPID() for the same org name, the update is rejected. MSP IDs are identity anchors for the network; silently swapping them would allow impersonation or break signature verification.","triggerScenarios":"Submitting a channel config update where an organization under the Orderer group keeps its name but its MSP ID (the value in its MSP config value, org.MSPID(), derived from the config 'MSP' value / configtx 'ID' field) differs from the current config.","commonSituations":"Copy-paste typos in configtx.yaml where an org's ID was edited; reusing an org name for a different organization with a new MSP; merging configs from different networks where the same org name maps to different MSP IDs; accidentally regenerating crypto material under a different MSP name.","solutions":["Keep the MSP ID in the new config identical to the current one for that org name (check with configtxlator decode of both current and updated configs).","If the org truly needs a new MSP ID, create a NEW organization with a different name and add it, then remove the old one through the proper update sequence.","Fix any typo in the org's 'ID:' field in configtx.yaml and regenerate the update transaction.","Compare 'fabric channel fetch config' output before/after your edit to spot the MSP ID delta before submitting."],"exampleFix":"// before (configtx.yaml)\n- &OrdererOrg\n  Name: OrdererOrg\n  ID: NewOrdererMSP   # changed from OrdererMSP\n// after\n- &OrdererOrg\n  Name: OrdererOrg\n  ID: OrdererMSP      # MSP ID must stay immutable for existing orgs","handlingStrategy":"validation","validationCode":"// Verify orderer org MSP IDs are unchanged before proposing an update\nfunc checkMSPIDsUnchanged(current, proposed map[string]*cb.ConfigGroup) error {\n\tfor name, old := range current {\n\t\tnewG, ok := proposed[name]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\toldID := mspIDOf(old)\n\t\tif newID := mspIDOf(newG); oldID != \"\" && oldID != newID {\n\t\t\treturn fmt.Errorf(\"org %s MSP ID change detected: %s -> %s\", name, oldID, newID)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":"func orgHasMSPID(g *cb.ConfigGroup, want string) bool {\n\tv, ok := g.Values[\"MSP\"]\n\tif !ok || v == nil {\n\t\treturn false\n\t}\n\tvar msp mspconfig.MSPConfig\n\tif err := proto.Unmarshal(v.Value, &msp); err != nil {\n\t\treturn false\n\t}\n\treturn string(msp.Name) == want\n}","tryCatchPattern":"if err := configtxManager.ProposeConfigUpdate(env); err != nil {\n\tif strings.Contains(err.Error(), \"attempted to change MSP ID\") {\n\t\t// do not retry; restore the original MSP ID and regenerate the update\n\t\treturn fmt.Errorf(\"immutable MSP ID violation: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Treat MSP IDs as immutable: never edit the ID: field of an existing org in configtx.yaml","Always fetch and diff the live channel config against your proposed config before submitting","Give new organizations unique names instead of reusing names with new MSPs","Keep crypto material and configtx IDs in sync when regenerating certificates"],"tags":["hyperledger-fabric","msp","channel-config","config-update"],"backgroundTag":"immutable-msp-id-violation","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"}