{"record":{"id":"ee96a87f69f96442","repo":"hyperledger/fabric","slug":"private-data-is-forbidden-to-be-used-in-instantiat","errorCode":null,"errorMessage":"Private data is forbidden to be used in instantiate","messagePattern":"Private data is forbidden to be used in instantiate","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/endorser/endorser.go","lineNumber":212,"sourceCode":"\t\treturn res, nil, ccevent, nil, nil\n\t}\n\n\t// Note, this is a little goofy, as if there is private data, Done() gets called\n\t// early, so this is invoked multiple times, but that is how the code worked before\n\t// this change, so, should be safe.  Long term, let's move the Done up to the create.\n\tdefer txParams.TXSimulator.Done()\n\n\tsimResult, err := txParams.TXSimulator.GetTxSimulationResults()\n\tif err != nil {\n\t\te.Metrics.SimulationFailure.With(meterLabels...).Add(1)\n\t\treturn nil, nil, nil, nil, err\n\t}\n\n\tif simResult.PvtSimulationResults != nil {\n\t\tif chaincodeName == \"lscc\" {\n\t\t\t// TODO: remove once we can store collection configuration outside of LSCC\n\t\t\te.Metrics.SimulationFailure.With(meterLabels...).Add(1)\n\t\t\treturn nil, nil, nil, nil, errors.New(\"Private data is forbidden to be used in instantiate\")\n\t\t}\n\t\tpvtDataWithConfig, err := AssemblePvtRWSet(txParams.ChannelID, simResult.PvtSimulationResults, txParams.TXSimulator, e.Support.GetDeployedCCInfoProvider())\n\t\t// To read collection config need to read collection updates before\n\t\t// releasing the lock, hence txParams.TXSimulator.Done()  moved down here\n\t\ttxParams.TXSimulator.Done()\n\n\t\tif err != nil {\n\t\t\te.Metrics.SimulationFailure.With(meterLabels...).Add(1)\n\t\t\treturn nil, nil, nil, nil, errors.WithMessage(err, \"failed to obtain collections config\")\n\t\t}\n\t\tendorsedAt, err := e.Support.GetLedgerHeight(txParams.ChannelID)\n\t\tif err != nil {\n\t\t\te.Metrics.SimulationFailure.With(meterLabels...).Add(1)\n\t\t\treturn nil, nil, nil, nil, errors.WithMessage(err, fmt.Sprintf(\"failed to obtain ledger height for channel '%s'\", txParams.ChannelID))\n\t\t}\n\t\t// Add ledger height at which transaction was endorsed,\n\t\t// `endorsedAt` is obtained from the block storage and at times this could be 'endorsement Height + 1'.\n\t\t// However, since we use this height only to select the configuration (3rd parameter in distributePrivateData) and","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/endorser/endorser.go#L194-L230","documentation":"During simulation, if the transaction produced private-data writes (PvtSimulationResults) and the target chaincode is lscc, the endorser rejects the proposal: collection configuration in instantiate could not be stored outside LSCC at the time, so private data in instantiate is forbidden.","triggerScenarios":"Calling lscc instantiate/upgrade with a chaincode that defines collections, causing the simulation to write private data (collection config updates) which lscc proposals may not carry.","commonSituations":"Deploying a chaincode with collection-config via the legacy lscc path; old deployment scripts combining private collections with instantiate; missing the separate collection-config handling introduced later.","solutions":["Use the new lifecycle (_lifecycle) approve/commit flow where collection configuration is passed to commit","Remove private-data/collection definitions from the legacy instantiate path","Update tooling so collections are configured outside lscc"],"exampleFix":"// before\npeer chaincode instantiate -C mychannel -n mycc --collections-config collections.json ...\n// after\npeer lifecycle chaincode approveformyorg ... --collections-config collections.json\npeer lifecycle chaincode commit -C mychannel -n mycc ...","handlingStrategy":"validation","validationCode":"if chaincodeName == \"lscc\" && simResult.PvtSimulationResults != nil {\n    return errors.New(\"use _lifecycle commit with collections config instead\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass collection configuration via the _lifecycle commit flow, not legacy instantiate","Avoid chaincodes that write private data during legacy instantiate","Audit deploy scripts for lscc + collections combinations"],"tags":["endorser","private-data","collections","lifecycle"],"backgroundTag":"private-data-in-instantiate-forbidden","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"}