hyperledger/fabric · error

wasn't able to obtain private data, block sequence number %d

Error message

wasn't able to obtain private data, block sequence number %d, due to %s

What it means

fromLedger fetches private data by block number from the ledger via committer.GetPvtDataByNum. When the underlying ledger lookup fails (DB error, block not yet committed, iterator failure), this error reports the block sequence number and the wrapped cause. It is produced on the reconciliation path where the block is expected to exist in the ledger.

Source

Thrown at gossip/privdata/dataretriever.go:117

		return results, false, nil
	}
	// Since ledger height is above block sequence number private data is might be available in the ledger
	results, err := dr.fromLedger(digests, blockNum)
	return results, true, err
}

func (dr *dataRetriever) fromLedger(digests []*protosgossip.PvtDataDigest, blockNum uint64) (Dig2PvtRWSetWithConfig, error) {
	filter := make(map[string]ledger.PvtCollFilter)
	for _, dig := range digests {
		if _, ok := filter[dig.Namespace]; !ok {
			filter[dig.Namespace] = make(ledger.PvtCollFilter)
		}
		filter[dig.Namespace][dig.Collection] = true
	}

	pvtData, err := dr.committer.GetPvtDataByNum(blockNum, filter)
	if err != nil {
		return nil, errors.Errorf("wasn't able to obtain private data, block sequence number %d, due to %s", blockNum, err)
	}

	results := make(Dig2PvtRWSetWithConfig)
	for _, dig := range digests {
		pvtRWSetWithConfig := &util.PrivateRWSetWithConfig{}
		for _, data := range pvtData {
			if data.WriteSet == nil {
				dr.logger.Warning("Received nil write set for collection tx in block", data.SeqInBlock, "block number", blockNum)
				continue
			}

			// private data doesn't hold rwsets for namespace and collection or
			// belongs to different transaction
			if !data.Has(dig.Namespace, dig.Collection) || data.SeqInBlock != dig.SeqInBlock {
				continue
			}

			pvtRWSet := dr.extractPvtRWsets(data.WriteSet.NsPvtRwset, dig.Namespace, dig.Collection)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Wait for the local peer to catch up and commit the block, then retry (gossip reconciliation retries automatically).
  2. Verify the peer's ledger height with `peer channel getinfo` matches the requested blockNum.
  3. Check pvtdata store health and whether retention policies purged the block's private data.
  4. Inspect the wrapped %s cause for a concrete DB error and fix storage-level issues.

Example fix

// before: requesting pvt data for uncommitted block
pvtData, err := dr.committer.GetPvtDataByNum(blockNum, filter) // blockNum >= height

// after: clamp to current height
height, _ := dr.committer.LedgerHeight()
if blockNum >= height {
    return nil, nil // nothing reconcilable yet
}
pvtData, err := dr.committer.GetPvtDataByNum(blockNum, filter)
Defensive patterns

Strategy: retry

Validate before calling

height, err := committer.LedgerHeight()
if err != nil || blockNum >= height {
    return errors.New("block not committed locally; cannot reconcile yet")
}

Type guard

func blockAvailable(c privdata.Committer, blockNum uint64) bool {
    h, err := c.LedgerHeight()
    return err == nil && blockNum < h
}

Try / catch

pvtData, err := dr.committer.GetPvtDataByNum(blockNum, filter)
if err != nil {
    logger.Warningf("pvt data for seq %d unavailable (%v), scheduling reconciliation retry", blockNum, err)
    scheduleRetry(blockNum)
    return
}

Prevention

When it happens

Trigger: GetPvtDataByNum(blockNum, filter) fails: requesting pvt data for a block beyond local ledger height, ledger DB read error, or the pvt-data store hasn't reconciled that block yet.

Common situations: Reconciling with a peer that is ahead (local peer behind); pvtdata store pruned by retention policy; corrupted pvtdata index; request arriving before local commit of the block.

Related errors


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