{"record":{"id":"8308150534e30929","repo":"hyperledger/fabric","slug":"block-metadata-is-nil-or-block-metadata-lacks-a-tx","errorCode":null,"errorMessage":"Block.Metadata is nil or Block.Metadata lacks a Tx filter bitmap","messagePattern":"Block\\.Metadata is nil or Block\\.Metadata lacks a Tx filter bitmap","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gossip/privdata/coordinator.go","lineNumber":299,"sourceCode":"\t\t\t\tif !isAuthorized(peerAuthInfo) {\n\t\t\t\t\tc.logger.Debugf(\"Skipping collection criteria [%#v] because peer isn't authorized\", cc)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tseqs2Namespaces.addCollection(uint64(seqInBlock), txPvtDataItem.WriteSet.DataModel, ns.Namespace, col)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn blockAndPvtData.Block, seqs2Namespaces.asPrivateData(), nil\n}\n\n// getTxPvtdataInfoFromBlock parses the block transactions and returns the list of private data items in the block.\n// Note that this peer's eligibility for the private data is not checked here.\nfunc (c *coordinator) getTxPvtdataInfoFromBlock(block *common.Block) ([]*ledger.TxPvtdataInfo, error) {\n\ttxPvtdataItemsFromBlock := []*ledger.TxPvtdataInfo{}\n\n\tif block.Metadata == nil || len(block.Metadata.Metadata) <= int(common.BlockMetadataIndex_TRANSACTIONS_FILTER) {\n\t\treturn nil, errors.New(\"Block.Metadata is nil or Block.Metadata lacks a Tx filter bitmap\")\n\t}\n\ttxsFilter := txValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])\n\tdata := block.Data.Data\n\tif len(txsFilter) != len(block.Data.Data) {\n\t\treturn nil, errors.Errorf(\"block data size(%d) is different from Tx filter size(%d)\", len(block.Data.Data), len(txsFilter))\n\t}\n\n\tfor seqInBlock, txEnvBytes := range data {\n\t\tinvalid := txsFilter[seqInBlock] != uint8(peer.TxValidationCode_VALID)\n\t\ttxInfo, err := getTxInfoFromTransactionBytes(txEnvBytes)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tcolPvtdataInfo := []*ledger.CollectionPvtdataInfo{}\n\t\tfor _, ns := range txInfo.txRWSet.NsRwSets {\n\t\t\tfor _, hashedCollection := range ns.CollHashedRwSets {\n\t\t\t\t// skip if no writes","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/gossip/privdata/coordinator.go#L281-L317","documentation":"getTxPvtdataInfoFromBlock reads the transaction-filter bitmap stored in block.Metadata at index BlockMetadataIndex_TRANSACTIONS_FILTER to determine which txs are valid. If block.Metadata is nil, or the metadata array is too short to contain the filter, the block is considered malformed for private-data purposes and this error is returned.","triggerScenarios":"StoreBlock -> getTxPvtdataInfoFromBlock called with a block whose Metadata is nil or whose Metadata.Metadata slice has length <= BlockMetadataIndex_TRANSACTIONS_FILTER (index 2).","commonSituations":"Blocks produced by non-Fabric tooling or older/different fabric versions lacking the Tx filter metadata; hand-crafted test blocks without Metadata; corrupted blocks fetched from a misbehaving source.","solutions":["Use a full block produced by the ordering service including all standard metadata entries","Regenerate/repair the block with proper Metadata (esp. the TRANSACTIONS_FILTER entry)","Update tooling/versions so block generation matches the fabric proto expectations","In tests, populate block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]"],"exampleFix":"// before\nblk := &common.Block{Header: h, Data: d}\nc.StoreBlock(blk, nil)\n// after\nblk.Metadata = &common.BlockMetadata{\n    Metadata: make([][]byte, int(common.BlockMetadataIndex_TRANSACTIONS_FILTER)+1),\n}\nblk.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] =\n    bytes.Repeat([]byte{byte(peer.TxValidationCode_VALID)}, len(d.Data))\nc.StoreBlock(blk, nil)","handlingStrategy":"validation","validationCode":"func blockHasTxFilter(b *common.Block) bool {\n    return b.Metadata != nil &&\n        len(b.Metadata.Metadata) > int(common.BlockMetadataIndex_TRANSACTIONS_FILTER)\n}\nif !blockHasTxFilter(block) {\n    return errors.New(\"block lacks Tx filter metadata\")\n}","typeGuard":"func hasTxFilterMetadata(b *common.Block) bool {\n    return b != nil && b.Metadata != nil &&\n        len(b.Metadata.Metadata) > int(common.BlockMetadataIndex_TRANSACTIONS_FILTER) &&\n        len(b.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) > 0\n}","tryCatchPattern":null,"preventionTips":["Always build blocks with the full standard metadata array in tests/tools","Keep block-producing tooling aligned with the fabric proto version","Reject blocks lacking metadata at ingestion, before StoreBlock","Never strip Metadata when exporting/importing blocks"],"tags":["gossip","privdata","block-metadata","validation"],"backgroundTag":"malformed-block-metadata","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"}