{"record":{"id":"4bf02a50167ba30e","repo":"hyperledger/fabric","slug":"invalid-block-s-channel-id-expected-s-given","errorCode":null,"errorMessage":"Invalid block's channel id. Expected [%s]. Given [%s]","messagePattern":"Invalid block's channel id\\. Expected \\[(.+?)\\]\\. Given \\[(.+?)\\]","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/peer/gossip/mcs.go","lineNumber":145,"sourceCode":"// else returns error\nfunc (s *MSPMessageCryptoService) VerifyBlock(chainID common.ChannelID, seqNum uint64, block *pcommon.Block) error {\n\tif block.Header == nil {\n\t\treturn fmt.Errorf(\"Invalid Block on channel [%s]. Header must be different from nil.\", chainID)\n\t}\n\n\tblockSeqNum := block.Header.Number\n\tif seqNum != blockSeqNum {\n\t\treturn fmt.Errorf(\"Claimed seqNum is [%d] but actual seqNum inside block is [%d]\", seqNum, blockSeqNum)\n\t}\n\n\t// - Extract channelID and compare with chainID\n\tchannelID, err := protoutil.GetChannelIDFromBlock(block)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed getting channel id from block with id [%d] on channel [%s]: [%s]\", block.Header.Number, chainID, err)\n\t}\n\n\tif channelID != string(chainID) {\n\t\treturn fmt.Errorf(\"Invalid block's channel id. Expected [%s]. Given [%s]\", chainID, channelID)\n\t}\n\n\t// - Unmarshal medatada\n\tif block.Metadata == nil || len(block.Metadata.Metadata) == 0 {\n\t\treturn fmt.Errorf(\"Block with id [%d] on channel [%s] does not have metadata. Block not valid.\", block.Header.Number, chainID)\n\t}\n\n\tdataHash, err := protoutil.BlockDataHash(block.Data)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// - Verify that Header.DataHash is equal to the hash of block.Data\n\t// This is to ensure that the header is consistent with the data carried by this block\n\tif !bytes.Equal(dataHash, block.Header.DataHash) {\n\t\treturn fmt.Errorf(\"Header.DataHash is different from Hash(block.Data) for block with id [%d] on channel [%s]\", block.Header.Number, chainID)\n\t}\n\n\treturn s.verifyHeaderAndMetadata(channelID, block)","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/internal/peer/gossip/mcs.go#L127-L163","documentation":"VerifyBlock checks that the block's channel ID (extracted from its header/metadata) matches the channel on which the block was claimed. This error reports the expected channel vs the channel encoded in the block. It is a security check preventing cross-channel block injection via gossip.","triggerScenarios":"VerifyBlock(chainID, seq, block) where block's embedded channelID differs from string(chainID) — e.g. block pulled from channel A but validated against channel B.","commonSituations":"Malicious or buggy peer sending blocks across channels; developer wiring wrong channel name when programmatically invoking the crypto service; channel renamed/recreated while peer still holds old blocks.","solutions":["Ensure the caller passes the channel ID that matches the block's origin channel","Check gossip membership/config — the peer may have stale state for a deleted or recreated channel","Inspect the block with configtxlator or a decoder to confirm its true channel"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func assertChannel(b *pcommon.Block, chainID common.ChannelID) error {\n    ch, err := protoutil.GetChannelIDFromBlock(b)\n    if err != nil {\n        return err\n    }\n    if ch != string(chainID) {\n        return fmt.Errorf(\"block belongs to channel %s, expected %s\", ch, chainID)\n    }\n    return nil\n}","typeGuard":"func belongsToChannel(b *pcommon.Block, chainID common.ChannelID) bool {\n    ch, err := protoutil.GetChannelIDFromBlock(b)\n    return err == nil && ch == string(chainID)\n}\n\nif !belongsToChannel(block, chainID) {\n    return errors.New(\"block/channel mismatch, refusing verify\")\n}","tryCatchPattern":"if err := cryptoService.VerifyBlock(chainID, seqNum, block); err != nil {\n    if strings.Contains(err.Error(), \"Invalid block's channel id\") {\n        log.Errorf(\"possible cross-channel injection on %s: %v\", chainID, err)\n        return err\n    }\n    return err\n}","preventionTips":["Never reuse block objects across channels in code or tests","Audit gossip membership config when adding/removing channels","Alert on this error — it can indicate a malicious or misconfigured peer"],"tags":["fabric","gossip","security","channel-mismatch"],"backgroundTag":"channel-id-mismatch","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"}