{"record":{"id":"0d95b192d0b9ce88","repo":"hyperledger/fabric","slug":"illegal-orderer-config-update-detected-endpoints","errorCode":null,"errorMessage":"illegal orderer config update detected: endpoints of org %s are missing","messagePattern":"illegal orderer config update detected: endpoints of org (.+?) are missing","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/channelconfig/bundle.go","lineNumber":102,"sourceCode":"\t\tif !ok {\n\t\t\treturn errors.New(\"current config has orderer section, but new config does not\")\n\t\t}\n\n\t\t// Prevent consensus-type migration when channel capabilities ConsensusTypeMigration is disabled\n\t\tif !b.channelConfig.Capabilities().ConsensusTypeMigration() {\n\t\t\tif oc.ConsensusType() != noc.ConsensusType() {\n\t\t\t\treturn errors.Errorf(\"attempted to change consensus type from %s to %s\",\n\t\t\t\t\toc.ConsensusType(), noc.ConsensusType())\n\t\t\t}\n\t\t}\n\n\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()","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/channelconfig/bundle.go#L84-L120","documentation":"This error comes from Hyperledger Fabric's channelconfig bundle validation (ValidateNew in common/channelconfig/bundle.go). When a config update attempts to switch a channel's consensus type to BFT (the new V3 capability is enabled while the old one was not), every orderer organization in the new config must declare endpoints. If an orderer org in the proposed config has an empty Endpoints() list, the update is rejected because BFT consensus requires peers to know each orderer's address.","triggerScenarios":"A channel config update transaction (via configtxgen/configtxlator or the orderer's configuration update path) where the new config enables ConsensusTypeBFT capability (e.g. moving capabilities from V2.x to V3.0 / BFT) while at least one OrdererGroup organization's config lacks the 'Endpoints' key in its Orderer section (org.Endpoints() returns empty).","commonSituations":"Upgrading a network to Fabric 3.0 / BFT consensus (e.g. switching etcdraft->smartbft or enabling V3_0 channel capability); generating a new channel config where an orderer org was defined in the 'Organizations' list of the Orderer group without an 'Endpoints' field in its Orderer section; copying org definitions from the Consortiums section (which has no endpoints) into the orderer group.","solutions":["Add the 'Endpoints' key to the Orderer section of every orderer organization in the new config (e.g. Endpoints: - orderer.example.com:7050) and regenerate the config.","Run configtxlator to decode the proposed config and verify each org under channel->group->Orderer->groups has a value under 'Orderer->values->Endpoints'.","Verify channel capabilities: if you are enabling V3_0/BFT capability in the same update, ensure the config diff includes endpoints for ALL orderer orgs before submitting.","If the org genuinely needs no orderer endpoints, remove it from the Orderer group's Organizations rather than leaving it empty."],"exampleFix":"// before (configtx.yaml, orderer org without endpoints in Orderer section)\nOrderer:\n  Organizations:\n    - &OrdererOrg\n      Name: OrdererOrg\n      ID: OrdererMSP\n      MSPDir: msp\n// after\nOrderer:\n  Organizations:\n    - &OrdererOrg\n      Name: OrdererOrg\n      ID: OrdererMSP\n      MSPDir: msp\n      OrdererEndpoints:\n        - orderer.example.com:7050","handlingStrategy":"validation","validationCode":"// Before submitting a config update, decode the new config and check orderer org endpoints\nfunc validateOrdererEndpoints(newConfig *cb.Config) error {\n\tordererGroup, ok := newConfig.Groups[\"Orderer\"]\n\tif !ok {\n\t\treturn nil\n\t}\n\tfor orgName, orgGroup := range ordererGroup.Groups {\n\t\tepVal, ok := orgGroup.Values[\"Endpoints\"]\n\t\tif !ok || epVal == nil {\n\t\t\treturn fmt.Errorf(\"org %s has no Endpoints value; BFT capability requires it\", orgName)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":"func hasEndpoints(orgGroup *cb.ConfigGroup) bool {\n\tv, ok := orgGroup.Values[\"Endpoints\"]\n\treturn ok && v != nil\n}","tryCatchPattern":"// Fabric returns errors from Update/Validate rather than panics\nif err := configtxManager.ProposeConfigUpdate(env); err != nil {\n\tif strings.Contains(err.Error(), \"endpoints of org\") {\n\t\t// fail fast: fix configtx and regenerate update, do not retry\n\t\treturn fmt.Errorf(\"config update rejected: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Always define OrdererEndpoints in configtx.yaml for every orderer org used in the Orderer group","Diff current vs proposed config JSON with configtxlator before submitting any update","When enabling V3_0/BFT capability, inventory all orderer orgs first and confirm each has endpoints","Use configtxgen's validate mode to lint profiles before generating update transactions"],"tags":["hyperledger-fabric","channel-config","bft","config-update"],"backgroundTag":"missing-endpoint-config","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"}