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, errView on GitHub (pinned to 2736b63f8f)
Solutions
- Merge read-write sets per namespace (union reads/writes) before building the txrwset instead of appending duplicate NsRwSets entries.
- Check any custom endorser or rwset-aggregating tooling for append-without-dedup logic.
- Use the standard SDK/endorser path that constructs one NsRwSet per namespace.
- 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
- Merge rwsets per namespace instead of appending.
- Avoid custom rwset aggregation code.
- Use the standard endorser path to build transactions.
- Decode and inspect rwsets in tooling before submission.
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
- '%s' not equal <newest|oldest|config|(number)>
- unmarshalling block: %s
- specified --channelID %s does not match channel ID %s in con
- unmarshalling envelope: %s
- specified --channelID %s does not match channel ID %s in con
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/cc423cc88f64fd91.
Report an issue: GitHub.