hyperledger/fabric · error

block data size(%d) is different from Tx filter size(%d)

Error message

block data size(%d) is different from Tx filter size(%d)

What it means

getTxPvtdataInfoFromBlock cross-checks the length of the Tx validation filter bitmap against the number of transactions in block.Data.Data. Each tx in the block must have exactly one validation flag byte; a size mismatch means the block is internally inconsistent and cannot be safely processed, so this error is returned.

Source

Thrown at gossip/privdata/coordinator.go:304

			}
		}
	}

	return blockAndPvtData.Block, seqs2Namespaces.asPrivateData(), nil
}

// getTxPvtdataInfoFromBlock parses the block transactions and returns the list of private data items in the block.
// Note that this peer's eligibility for the private data is not checked here.
func (c *coordinator) getTxPvtdataInfoFromBlock(block *common.Block) ([]*ledger.TxPvtdataInfo, error) {
	txPvtdataItemsFromBlock := []*ledger.TxPvtdataInfo{}

	if block.Metadata == nil || len(block.Metadata.Metadata) <= int(common.BlockMetadataIndex_TRANSACTIONS_FILTER) {
		return nil, errors.New("Block.Metadata is nil or Block.Metadata lacks a Tx filter bitmap")
	}
	txsFilter := txValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
	data := block.Data.Data
	if len(txsFilter) != len(block.Data.Data) {
		return nil, errors.Errorf("block data size(%d) is different from Tx filter size(%d)", len(block.Data.Data), len(txsFilter))
	}

	for seqInBlock, txEnvBytes := range data {
		invalid := txsFilter[seqInBlock] != uint8(peer.TxValidationCode_VALID)
		txInfo, err := getTxInfoFromTransactionBytes(txEnvBytes)
		if err != nil {
			continue
		}

		colPvtdataInfo := []*ledger.CollectionPvtdataInfo{}
		for _, ns := range txInfo.txRWSet.NsRwSets {
			for _, hashedCollection := range ns.CollHashedRwSets {
				// skip if no writes
				if !containsWrites(txInfo.txID, ns.NameSpace, hashedCollection) {
					continue
				}
				cc := privdata.CollectionCriteria{
					Channel:    txInfo.channelID,

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Re-obtain the intact block from the orderer or another peer
  2. Fix the block repair/conversion tooling to keep the Tx filter in sync with block data length
  3. Rebuild the filter bitmap (one TxValidationCode byte per tx) if you must repair locally
  4. Correct test fixtures so filter length equals len(block.Data.Data)

Example fix

// before
filter := []byte{0x00} // only 1 flag, but 3 txs
// after
filter := bytes.Repeat([]byte{byte(peer.TxValidationCode_VALID)}, len(block.Data.Data))
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = filter
Defensive patterns

Strategy: validation

Validate before calling

filter := block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]
if len(filter) != len(block.Data.Data) {
    return fmt.Errorf("filter size %d != tx count %d", len(filter), len(block.Data.Data))
}

Type guard

func txFilterConsistent(b *common.Block) bool {
    if b == nil || b.Metadata == nil || b.Data == nil ||
        len(b.Metadata.Metadata) <= int(common.BlockMetadataIndex_TRANSACTIONS_FILTER) {
        return false
    }
    return len(b.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) == len(b.Data.Data)
}

Prevention

When it happens

Trigger: StoreBlock -> getTxPvtdataInfoFromBlock where len(block.Metadata.Metadata[TRANSACTIONS_FILTER]) != len(block.Data.Data) — e.g. metadata truncated/rebuilt separately from data, or txs added/removed without updating the filter.

Common situations: Ledger repair or export/import tools that rewrote block.Data but not the metadata filter; corrupted block from gossip; custom block builders; tests with mismatched fixture data.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/a11ce07c71504048. Report an issue: GitHub.