{"record":{"id":"e328c4216a4baedd","repo":"hyperledger/fabric","slug":"next-config-attempted-to-change-consensustype-type","errorCode":null,"errorMessage":"next config attempted to change ConsensusType.Type from %s to %s, but capability is disabled","messagePattern":"next config attempted to change ConsensusType\\.Type from (.+?) to (.+?), but capability is disabled","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/msgprocessor/maintenancefilter.go","lineNumber":99,"sourceCode":"\t\treturn errors.Errorf(\"updated config does not include a config update\")\n\t}\n\n\tbundle, err := channelconfig.NewBundle(mf.support.ChannelID(), configEnvelope.Config, mf.bccsp)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"failed to parse config\")\n\t}\n\n\tnextOrdererConfig, ok := bundle.OrdererConfig()\n\tif !ok {\n\t\treturn errors.New(\"next config is missing orderer group\")\n\t}\n\n\tif !ordererConfig.Capabilities().ConsensusTypeMigration() {\n\t\tif nextState := nextOrdererConfig.ConsensusState(); nextState != orderer.ConsensusType_STATE_NORMAL {\n\t\t\treturn errors.Errorf(\"next config attempted to change ConsensusType.State to %s, but capability is disabled\", nextState)\n\t\t}\n\t\tif ordererConfig.ConsensusType() != nextOrdererConfig.ConsensusType() {\n\t\t\treturn errors.Errorf(\"next config attempted to change ConsensusType.Type from %s to %s, but capability is disabled\",\n\t\t\t\tordererConfig.ConsensusType(), nextOrdererConfig.ConsensusType())\n\t\t}\n\t\treturn nil\n\t}\n\n\t// Entry to- and exit from- maintenance-mode should not be accompanied by any other change.\n\tif ordererConfig.ConsensusState() != nextOrdererConfig.ConsensusState() {\n\t\tif err1Change := mf.ensureConsensusTypeChangeOnly(configEnvelope); err1Change != nil {\n\t\t\treturn err1Change\n\t\t}\n\t\tif ordererConfig.ConsensusType() != nextOrdererConfig.ConsensusType() {\n\t\t\treturn errors.Errorf(\"attempted to change ConsensusType.Type from %s to %s, but ConsensusType.State is changing from %s to %s\",\n\t\t\t\tordererConfig.ConsensusType(), nextOrdererConfig.ConsensusType(), ordererConfig.ConsensusState(), nextOrdererConfig.ConsensusState())\n\t\t}\n\t\tif !bytes.Equal(nextOrdererConfig.ConsensusMetadata(), ordererConfig.ConsensusMetadata()) {\n\t\t\treturn errors.Errorf(\"attempted to change ConsensusType.Metadata, but ConsensusType.State is changing from %s to %s\",\n\t\t\t\tordererConfig.ConsensusState(), nextOrdererConfig.ConsensusState())\n\t\t}","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/msgprocessor/maintenancefilter.go#L81-L117","documentation":"inspect rejects a config update that changes orderer ConsensusType.Type while the ConsensusTypeMigration capability is disabled. The consensus type (e.g. etcdraft, BFT) is immutable on channels lacking the migration capability.","triggerScenarios":"Submitting a config update that changes the Orderer group's ConsensusType.Type (e.g. etcdraft to BFT) while ConsensusTypeMigration capability is not enabled on the channel.","commonSituations":"Attempting a consensus-type change on a channel created with pre-migration capabilities; mixing the capability enablement and type change into one update instead of separate steps.","solutions":["Enable the ConsensusTypeMigration capability first in its own config update","Then enter STATE_MAINTENANCE, change the type, and exit maintenance in separate sequential updates","Confirm the current type matches expectation before submitting (don't resend an old update after capability enablement changed type)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"oc, _ := support.OrdererConfig()\nif !oc.Capabilities().ConsensusTypeMigration() && nextType != oc.ConsensusType() {\n\treturn errors.New(\"cannot change consensus type: migration capability disabled\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Enable migration capability before attempting type changes","Keep type constant in the maintenance entry/exit updates","Sequence: capability → enter maintenance → change type → exit maintenance"],"tags":["ordering","capability","consensus-type","migration"],"backgroundTag":"migration-capability-disabled","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"}