{"record":{"id":"753fa326bb097865","repo":"hyperledger/fabric","slug":"lscc-can-only-issue-a-single-putstate-upon-deploy-753fa3","errorCode":null,"errorMessage":"LSCC can only issue a single putState upon deploy","messagePattern":"LSCC can only issue a single putState upon deploy","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/handlers/validation/builtin/v13/lscc_validation_logic.go","lineNumber":512,"sourceCode":"\t\t\t/* security check 1 - cc not in the LCCC table of instantiated cc */\n\t\t\t/******************************************************************/\n\t\t\tif ccExistsOnLedger {\n\t\t\t\treturn policyErr(fmt.Errorf(\"Chaincode %s is already instantiated\", cdsArgs.ChaincodeSpec.ChaincodeId.Name))\n\t\t\t}\n\n\t\t\t/****************************************************************************/\n\t\t\t/* security check 2 - validation of rwset (and of collections if enabled) */\n\t\t\t/****************************************************************************/\n\t\t\tif ac.PrivateChannelData() {\n\t\t\t\t// do extra validation for collections\n\t\t\t\terr := vscc.validateRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, lsccFunc, ac, chid)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// there can only be a single ledger write\n\t\t\t\tif len(lsccrwset.Writes) != 1 {\n\t\t\t\t\treturn policyErr(fmt.Errorf(\"LSCC can only issue a single putState upon deploy\"))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*****************************************************/\n\t\t\t/* security check 3 - check the instantiation policy */\n\t\t\t/*****************************************************/\n\t\t\tpol := cdRWSet.InstantiationPolicy\n\t\t\tif pol == nil {\n\t\t\t\treturn policyErr(fmt.Errorf(\"no instantiation policy was specified\"))\n\t\t\t}\n\t\t\t// FIXME: could we actually pull the cds package from the\n\t\t\t// file system to verify whether the policy that is specified\n\t\t\t// here is the same as the one on disk?\n\t\t\t// PROS: we prevent attacks where the policy is replaced\n\t\t\t// CONS: this would be a point of non-determinism\n\t\t\terr := vscc.checkInstantiationPolicy(chid, env, pol, payl)\n\t\t\tif err != nil {\n\t\t\t\treturn err","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/handlers/validation/builtin/v13/lscc_validation_logic.go#L494-L530","documentation":"On the DEPLOY path, when private channel data (collections) is not enabled, lscc's write-set must contain exactly one write — the ChaincodeData putState. Any additional (or zero) writes means the transaction does not conform to the expected deploy semantics and is rejected.","triggerScenarios":"An lscc deploy whose lscc-namespaced rwset contains 0 or 2+ writes — e.g. a modified lscc emitting extra puts, or a hand-crafted rwset for testing.","commonSituations":"Patched/custom lscc implementations writing extra keys on deploy, integration tests fabricating lscc rwsets manually, mixing deploy-time collection configuration with a non-private-data channel code path.","solutions":["Use the stock lscc implementation so deploy writes exactly one ChaincodeData record.","If you modified lscc, move any extra writes out of the deploy path.","For hand-built test rwsets, ensure exactly one write on the lscc namespace with a valid ChaincodeData value.","Enable/align private-channel-data handling consistently across peers if collections are intended."],"exampleFix":"// before (custom lscc)\nstub.PutState(ccname, cdBytes)\nstub.PutState(ccname+\"~meta\", metaBytes) // extra write\n// after\nstub.PutState(ccname, cdBytes) // single write only","handlingStrategy":"validation","validationCode":"// pre-flight on custom lscc rwsets\nlsccWrites := countWrites(nsRwSet[\"lscc\"])\nif lsccWrites != 1 {\n    return fmt.Errorf(\"lscc deploy must write exactly 1 key, got %d\", lsccWrites)\n}","typeGuard":"func isSingleWrite(ns *rwset.NsRwSet) bool { return ns != nil && len(ns.KvRwSet.Writes) == 1 }","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"single putState upon deploy\") { /* strip extra writes from the deploy rwset or use stock lscc */ }","preventionTips":["Run stock lscc on all peers","Review any lscc patches for extra writes","Validate fabricated test rwsets against the one-write contract"],"tags":["hyperledger-fabric","lscc","rwset","deploy"],"backgroundTag":"invalid-lscc-rwset","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}