hyperledger/fabric · error · VSCCEndorsementPolicyError
No read write set for lscc was found
Error message
No read write set for lscc was found
What it means
During V1.2 endorsement validation, ValidateLSCCInvocation checks that a deploy/upgrade transaction actually contains a read-write set for the lifecycle system chaincode (lscc). If the lscc namespace rwset is entirely absent (nil), the transaction is rejected as a policy error. This guards against transactions claiming to deploy a chaincode without the corresponding ledger update lscc performs.
Source
Thrown at core/handlers/validation/builtin/v12/validation_logic.go:599
logger.Debugf("Namespace %s", ns.NameSpace)
if ns.NameSpace == "lscc" {
lsccrwset = ns.KvRwSet
break
}
}
// retrieve from the ledger the entry for the chaincode at hand
cdLedger, ccExistsOnLedger, err := vscc.getInstantiatedCC(chid, cdsArgs.ChaincodeSpec.ChaincodeId.Name)
if err != nil {
return &commonerrors.VSCCExecutionFailureError{Err: err}
}
/******************************************/
/* security check 0 - validation of rwset */
/******************************************/
// there has to be a write-set
if lsccrwset == nil {
return policyErr(fmt.Errorf("No read write set for lscc was found"))
}
// there must be at least one write
if len(lsccrwset.Writes) < 1 {
return policyErr(fmt.Errorf("LSCC must issue at least one single putState upon deploy/upgrade"))
}
// the first key name must be the chaincode id provided in the deployment spec
if lsccrwset.Writes[0].Key != cdsArgs.ChaincodeSpec.ChaincodeId.Name {
return policyErr(fmt.Errorf("expected key %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, lsccrwset.Writes[0].Key))
}
// the value must be a ChaincodeData struct
cdRWSet := &ccprovider.ChaincodeData{}
err = proto.Unmarshal(lsccrwset.Writes[0].Value, cdRWSet)
if err != nil {
return policyErr(fmt.Errorf("unmarshalling of ChaincodeData failed, error %s", err))
}
// the chaincode name in the lsccwriteset must match the chaincode name in the deployment spec
if cdRWSet.Name != cdsArgs.ChaincodeSpec.ChaincodeId.Name {
return policyErr(fmt.Errorf("expected cc name %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, cdRWSet.Name))View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure the transaction is produced by the normal SDK/lscc flow so lscc's putState generates a proper lscc rwset entry.
- Verify all peers and chaincode use matching Fabric versions so endorsement generates the expected lscc writes.
- Rebuild and resubmit the deploy/upgrade transaction using a current fabric-sdk-node/java/go release.
- Inspect the submitted envelope's TxRWSet (decode with peer or fabric-tools) to confirm the lscc namespace write exists before resubmitting.
Example fix
// before: crafting a proposal that skips lscc writes
invoke('lscc', 'deploy', args) // rwset missing
// after: use the standard lifecycle call so lscc issues its putState
client.installChaincode(...) ; client.instantiateChaincode({ chaincodeId, fcn: 'init' }) Defensive patterns
Strategy: validation
Validate before calling
// Go (peer-side concept): decode the envelope's TxRWSet and check before relying on lscc validation
rwSet, err := rwset.TxRwSetFromProtoBytes(txPayloadData)
if err != nil { return err }
if rwSet.GetNsRwSet("lscc") == nil {
return fmt.Errorf("transaction lacks lscc rwset; resubmit via standard instantiate flow")
} Type guard
func hasLsccRwSet(txRWSet *rwset.TxRwSet) bool {
return txRWSet != nil && txRWSet.GetNsRwSet("lscc") != nil
} Try / catch
if err := submitTx(envelope); err != nil {
if strings.Contains(err.Error(), "No read write set for lscc was found") {
// rebuild the instantiate/upgrade proposal with a current SDK and re-endorse
}
} Prevention
- Always instantiate/upgrade via SDK lifecycle APIs, never hand-crafted envelopes
- Keep peer and SDK versions aligned
- Decode and inspect the rwset before submitting deploy transactions
When it happens
Trigger: A transaction invokes lscc (deploy/upgrade) but the transaction's rwset contains no namespace rw-set for "lscc" at all, so the validator's txRWSet.GetNsRwSet("lscc") returns nil and it is passed as lsccrwset.
Common situations: Malformed or hand-crafted transactions submitted directly to orderer; endorsing peers running incompatible chaincode/validation code versions; rwset discarded or truncated by a broken endorsement pipeline; replaying a transaction that lost its lscc writes.
Related errors
- LSCC invocation is attempting to write to namespace %s
- malformed chaincode invocation spec
- LSCC must issue at least one single putState upon deploy/upg
- expected key %s, found %s
- expected cc name %s, found %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/15391daa708300a0.
Report an issue: GitHub.