hyperledger/fabric · error

hash of pvt data for collection [%s:%s] does not match with

Error message

hash of pvt data for collection [%s:%s] does not match with the corresponding hash in the public data. public hash = [%#v], pvt data hash = [%#v]

What it means

validatePvtdata compared the hash of a collection's private writeset against the hash committed in the public rwset for that transaction and they differ — the private data being validated does not correspond to what the transaction committed, indicating corruption, wrong data, or a tampering attempt.

Source

Thrown at core/ledger/kvledger/txmgmt/validation/batch_preparer.go:183

// TODO for now always return true. Add capability of checking if this data was produced by
// the validating peer itself during simulation and in that case return false
func requiresPvtdataValidation(tx *ledger.TxPvtData) bool {
	return true
}

// validatePvtdata returns true if hashes of all the collections writeset present in the pvt data
// match with the corresponding hashes present in the public read-write set
func validatePvtdata(tx *transaction, pvtdata *ledger.TxPvtData) error {
	if pvtdata.WriteSet == nil {
		return nil
	}

	for _, nsPvtdata := range pvtdata.WriteSet.NsPvtRwset {
		for _, collPvtdata := range nsPvtdata.CollectionPvtRwset {
			collPvtdataHash := util.ComputeHash(collPvtdata.Rwset)
			hashInPubdata := tx.retrieveHash(nsPvtdata.Namespace, collPvtdata.CollectionName)
			if !bytes.Equal(collPvtdataHash, hashInPubdata) {
				return errors.Errorf(`hash of pvt data for collection [%s:%s] does not match with the corresponding hash in the public data. public hash = [%#v], pvt data hash = [%#v]`,
					nsPvtdata.Namespace, collPvtdata.CollectionName, hashInPubdata, collPvtdataHash)
			}
		}
	}
	return nil
}

// preprocessProtoBlock parses the proto instance of block into 'Block' structure.
// The returned 'Block' structure contains only transactions that are endorser transactions and are not already marked as invalid
func preprocessProtoBlock(postOrderSimulatorProvider PostOrderSimulatorProvider,
	validateKVFunc func(key string, value []byte) error,
	blk *common.Block, doMVCCValidation bool,
	customTxProcessors map[common.HeaderType]ledger.CustomTxProcessor,
) (*block, []*TxStatInfo, error) {
	b := &block{num: blk.Header.Number}
	txsStatInfo := []*TxStatInfo{}
	// Committer validator has already set validation flags based on well formed tran checks
	txsFilter := txflags.ValidationFlags(blk.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure the pvtdata distributed/collected matches what was endorsed at simulation time
  2. Reconcile private data from endorsing peers and re-validate
  3. Investigate for mismatched collection configs between endorsers and committer
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at core/ledger/kvledger/txmgmt/validation/batch_preparer.go:183 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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