hyperledger/fabric · error

duplicate namespace '%s' in txRWSet

Error message

duplicate namespace '%s' in txRWSet

What it means

Dispatch found the same namespace appearing more than once in the transaction's NsRwSets. Duplicate namespaces would double-count reads/writes, so Fabric rejects the tx with TxValidationCode_ILLEGAL_WRITESET. This indicates a corrupted or maliciously crafted read-write set.

Source

Thrown at core/committer/txvalidator/v20/plugindispatcher/dispatcher.go:177

	wrNamespace := map[string]bool{}
	wrNamespace[ccID] = true
	if respPayload.Events != nil {
		ccEvent := &peer.ChaincodeEvent{}
		if err = proto.Unmarshal(respPayload.Events, ccEvent); err != nil {
			return peer.TxValidationCode_INVALID_OTHER_REASON, errors.Wrapf(err, "invalid chaincode event")
		}
		if ccEvent.ChaincodeId != ccID {
			return peer.TxValidationCode_INVALID_OTHER_REASON, errors.Errorf("chaincode event chaincode id does not match chaincode action chaincode id")
		}
	}

	namespaces := make(map[string]struct{})
	for _, ns := range txRWSet.NsRwSets {
		// check to make sure there is no duplicate namespace in txRWSet
		if _, ok := namespaces[ns.NameSpace]; ok {
			logger.Errorf("duplicate namespace '%s' in txRWSet", ns.NameSpace)
			return peer.TxValidationCode_ILLEGAL_WRITESET,
				errors.Errorf("duplicate namespace '%s' in txRWSet", ns.NameSpace)
		}
		namespaces[ns.NameSpace] = struct{}{}

		if v.txWritesToNamespace(ns) {
			wrNamespace[ns.NameSpace] = true
		}
	}

	// we've gathered all the info required to proceed to validation;
	// validation will behave differently depending on the chaincode

	// validate *EACH* read write set according to its chaincode's endorsement policy
	for ns := range wrNamespace {
		// Get latest chaincode validation plugin name and policy
		validationPlugin, args, err := v.GetInfoForValidate(chdr, ns)
		if err != nil {
			logger.Errorf("GetInfoForValidate for txId = %s returned error: %+v", chdr.TxId, err)
			return peer.TxValidationCode_INVALID_CHAINCODE, err

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Merge read-write sets per namespace (union reads/writes) before building the txrwset instead of appending duplicate NsRwSets entries.
  2. Check any custom endorser or rwset-aggregating tooling for append-without-dedup logic.
  3. Use the standard SDK/endorser path that constructs one NsRwSet per namespace.
  4. Inspect the failing tx's rwset with protos to identify the duplicated namespace and its producer.

Example fix

// before
rwSet.NsRwSets = append(rwSet.NsRwSets, nsA, nsA)
// after
if _, ok := seen[nsA.NameSpace]; !ok { rwSet.NsRwSets = append(rwSet.NsRwSets, nsA); seen[nsA.NameSpace] = true }
Defensive patterns

Strategy: validation

Validate before calling

const seen = new Set(); for (const ns of rwSet.nsRwSets) { if (seen.has(ns.nameSpace)) throw new Error(`duplicate namespace ${ns.nameSpace}`); seen.add(ns.nameSpace); }

Try / catch

try { validate(tx); } catch (err) { if (/duplicate namespace/.test(err.message)) { /* merge rwsets by namespace and rebuild tx */ } else { throw err; } }

Prevention

When it happens

Trigger: txRWSet.NsRwSets contains two entries with the same NameSpace for one transaction — malformed rwset assembly by a custom endorser/plugin, or rwsets merged/concatenated incorrectly by client or tooling.

Common situations: Custom code that concatenates multiple proposal responses' rwsets without merging by namespace; buggy third-party validation plugins building txRWSet manually; corrupted serialized transactions.

Related errors


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