{"record":{"id":"25558fa053442e7c","repo":"hyperledger/fabric","slug":"attempted-to-change-consensustype-metadata-but-co","errorCode":null,"errorMessage":"attempted to change ConsensusType.Metadata, but ConsensusType.State is changing from %s to %s","messagePattern":"attempted to change ConsensusType\\.Metadata, but ConsensusType\\.State is changing from (.+?) to (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/msgprocessor/maintenancefilter.go","lineNumber":115,"sourceCode":"\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}\n\t}\n\n\t// ConsensusType.Type can only change in maintenance-mode, and only within the set of permitted types.\n\t// Note: only etcdraft to BFT transitions are supported.\n\tif ordererConfig.ConsensusType() != nextOrdererConfig.ConsensusType() {\n\t\tif ordererConfig.ConsensusState() == orderer.ConsensusType_STATE_NORMAL {\n\t\t\treturn errors.Errorf(\"attempted to change consensus type from %s to %s, but current config ConsensusType.State is not in maintenance mode\",\n\t\t\t\tordererConfig.ConsensusType(), nextOrdererConfig.ConsensusType())\n\t\t}\n\t\tif nextOrdererConfig.ConsensusState() == orderer.ConsensusType_STATE_NORMAL {\n\t\t\treturn errors.Errorf(\"attempted to change consensus type from %s to %s, but next config ConsensusType.State is not in maintenance mode\",\n\t\t\t\tordererConfig.ConsensusType(), nextOrdererConfig.ConsensusType())\n\t\t}\n\n\t\tif !mf.permittedTargetConsensusTypes[nextOrdererConfig.ConsensusType()] {\n\t\t\treturn errors.Errorf(\"attempted to change consensus type from %s to %s, transition not supported\",","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/msgprocessor/maintenancefilter.go#L97-L133","documentation":"inspect rejects a config update that changes ConsensusType.Metadata while ConsensusType.State is also changing. Maintenance-mode entry/exit must not be accompanied by any change other than the state itself (after ensureConsensusTypeChangeOnly, metadata must be byte-identical), so metadata (e.g. etcdraft consenters or BFT options) must be updated in a separate config update.","triggerScenarios":"A single Orderer-group update that both transitions ConsensusType.State and modifies ConsensusType.Metadata bytes.","commonSituations":"Editing consenters/TLS certs at the same time as entering maintenance; regenerating metadata (field ordering/whitespace) causing byte inequality despite semantic equality; combining exit-from-maintenance with metadata refresh.","solutions":["Make the state transition its own config update with metadata byte-identical to the current metadata","Perform metadata changes (e.g. BFT options) in a separate update while state is stable (in maintenance)","Copy the existing metadata value verbatim when creating the state-transition update"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if cur.ConsensusState() != next.ConsensusState() && !bytes.Equal(cur.ConsensusMetadata(), next.ConsensusMetadata()) {\n\treturn errors.New(\"metadata must be byte-identical during a state transition\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy the current metadata verbatim into state-transition updates","Do metadata edits as separate updates while in maintenance","Avoid re-serialization that alters byte ordering of metadata"],"tags":["ordering","consensus-metadata","maintenance-mode","config-update"],"backgroundTag":"consensus-type-migration-rule-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"}