{"record":{"id":"0db46916a0c32c97","repo":"hyperledger/fabric","slug":"cannot-read-config-update","errorCode":null,"errorMessage":"cannot read config update","messagePattern":"cannot read config update","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/util.go","lineNumber":188,"sourceCode":"\t\treturn envelope, nil\n\tdefault:\n\t\treturn nil, errors.Errorf(\"unexpected header type: %v\", channelHeader.GetType())\n\t}\n}\n\n// ConsensusMetadataFromConfigBlock reads consensus metadata updates from the configuration block\nfunc ConsensusMetadataFromConfigBlock(block *common.Block) (*etcdraft.ConfigMetadata, *orderer.ConsensusType, error) {\n\tif block == nil {\n\t\treturn nil, nil, errors.New(\"nil block\")\n\t}\n\n\tif !protoutil.IsConfigBlock(block) {\n\t\treturn nil, nil, errors.New(\"not a config block\")\n\t}\n\n\tconfigEnvelope, err := ConfigEnvelopeFromBlock(block)\n\tif err != nil {\n\t\treturn nil, nil, errors.Wrap(err, \"cannot read config update\")\n\t}\n\n\tpayload, err := protoutil.UnmarshalPayload(configEnvelope.GetPayload())\n\tif err != nil {\n\t\treturn nil, nil, errors.Wrap(err, \"failed to extract payload from config envelope\")\n\t}\n\t// get config update\n\tconfigUpdate, err := configtx.UnmarshalConfigUpdateFromPayload(payload)\n\tif err != nil {\n\t\treturn nil, nil, errors.Wrap(err, \"could not read config update\")\n\t}\n\n\treturn MetadataFromConfigUpdate(configUpdate)\n}\n\n// VerifyConfigMetadata validates Raft config metadata.\n// Note: ignores certificates expiration.\nfunc VerifyConfigMetadata(metadata *etcdraft.ConfigMetadata, verifyOpts x509.VerifyOptions) error {","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/util.go#L170-L206","documentation":"This wrapper is produced when ConfigEnvelopeFromBlock (called inside ConsensusMetadataFromConfigBlock) fails for any reason — nil block, envelope extraction failure, bad channel header, or wrong header type. The original cause is chained so the wrapped message shows the underlying failure.","triggerScenarios":"Any inner failure of ConfigEnvelopeFromBlock: nil block slipped past checks, corrupted envelope at index 0, unparseable channel header, header type not HeaderType_CONFIG, or legacy ORDERER_TRANSACTION type.","commonSituations":"Corrupt ledger blocks; onboarding with a legacy system-channel block; non-config blocks reaching the parser when call-site validation is bypassed.","solutions":["Read the wrapped inner error to identify the true cause (nil block / extract envelope / header type).","Re-fetch the config block from a healthy ordering node or snapshot and retry.","Validate the block before the call: non-nil, IsConfigBlock, and (if needed) header type HeaderType_CONFIG.","If corruption is recurring, check disk health of the ordering node's ledger directory."],"exampleFix":"// before\nmeta, _, err := ConsensusMetadataFromConfigBlock(block) // opaque 'cannot read config update'\n\n// after\nif block == nil || !protoutil.IsConfigBlock(block) {\n    return errors.New(\"invalid config block input\")\n}\nmeta, _, err := ConsensusMetadataFromConfigBlock(block)\nif err != nil {\n    logger.Errorf(\"config block %d failed: %s\", block.Header.Number, err) // inner cause now visible\n}","handlingStrategy":"try-catch","validationCode":"if block == nil || !protoutil.IsConfigBlock(block) {\n    return errors.New(\"invalid config block input\")\n}","typeGuard":"func parseableConfigBlock(block *common.Block) bool {\n    if block == nil || !protoutil.IsConfigBlock(block) {\n        return false\n    }\n    _, err := ConfigEnvelopeFromBlock(block)\n    return err == nil\n}","tryCatchPattern":"meta, _, err := ConsensusMetadataFromConfigBlock(block)\nif err != nil {\n    if strings.Contains(err.Error(), \"cannot read config update\") {\n        return errors.Wrap(err, \"config block unreadable; re-fetch from healthy orderer\")\n    }\n    return err\n}","preventionTips":["Unwrap the chained error to find the true root cause (nil, extraction, header type).","Validate non-nil + IsConfigBlock before calling to shrink the failure surface.","Treat recurring failures as ledger corruption; re-sync from a snapshot or peer orderer."],"tags":["hyperledger-fabric","etcdraft","config-block","error-wrapping"],"backgroundTag":"malformed-block-envelope","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"}