hyperledger/fabric · error
LSCC can only issue a single putState upon deploy
Error message
LSCC can only issue a single putState upon deploy
What it means
When private channel data (collections) is not enabled, lscc deploy must produce exactly one ledger write (the ChaincodeData record). Multiple writes in the lscc rwset violate the expected deploy semantics and are rejected.
Source
Thrown at core/handlers/validation/builtin/v12/validation_logic.go:654
/* security check 1 - cc not in the LCCC table of instantiated cc */
/******************************************************************/
if ccExistsOnLedger {
return policyErr(fmt.Errorf("Chaincode %s is already instantiated", cdsArgs.ChaincodeSpec.ChaincodeId.Name))
}
/****************************************************************************/
/* security check 2 - validation of rwset (and of collections if enabled) */
/****************************************************************************/
if ac.PrivateChannelData() {
// do extra validation for collections
err := vscc.validateRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, lsccFunc, ac, chid)
if err != nil {
return err
}
} else {
// there can only be a single ledger write
if len(lsccrwset.Writes) != 1 {
return policyErr(fmt.Errorf("LSCC can only issue a single putState upon deploy"))
}
}
/*****************************************************/
/* security check 3 - check the instantiation policy */
/*****************************************************/
pol := cdRWSet.InstantiationPolicy
if pol == nil {
return policyErr(fmt.Errorf("no instantiation policy was specified"))
}
// FIXME: could we actually pull the cds package from the
// file system to verify whether the policy that is specified
// here is the same as the one on disk?
// PROS: we prevent attacks where the policy is replaced
// CONS: this would be a point of non-determinism
err := vscc.checkInstantiationPolicy(chid, env, pol, payl)
if err != nil {
return errView on GitHub (pinned to 2736b63f8f)
Solutions
- Enable the V1_2 (or later) PrivateChannelData capability in the channel config if you need collections.
- Remove collection configuration arguments from the instantiate call when the channel lacks the capability.
- Run stock lscc so only a single ChaincodeData write is issued on non-capability channels.
- Align all peers' channel capability versions.
Example fix
// before request['collections-config'] = collectionsConfig // channel lacks PrivateChannelData capability // after: enable V1_2 capability in channel config, or drop collections config request = baseInstantiateRequest
Defensive patterns
Strategy: validation
Validate before calling
// client-side: only send collections config when the channel has the PrivateChannelData capability
if !channelConfig.Capabilities.PrivateChannelData() && request.CollectionsConfig != nil {
return fmt.Errorf("channel lacks PrivateChannelData capability; drop collections config or upgrade channel config")
} Type guard
func collectionsAllowed(ac capabilities.ApplicationCapabilities) bool {
return ac != nil && ac.PrivateChannelData()
} Try / catch
if err := submitTx(envelope); err != nil {
if strings.Contains(err.Error(), "can only issue a single putState upon deploy") {
// either enable V1_2 channel capability or remove collections-config from instantiate
}
} Prevention
- Enable V1_2+ application capabilities before using private data collections
- Only attach collections-config when the channel supports it
- Keep channel config and peer binaries version-consistent
When it happens
Trigger: lsccrwset.Writes has length != 1 during DEPLOY on a channel without PrivateChannelData — e.g. custom lscc writing collection configs to lscc's namespace on a channel where private data is disabled.
Common situations: Passing collection-config arguments to instantiate on a channel where the capability for private channel data is disabled; modified lscc; peer with mismatched channel capabilities (V1_2 vs V1_1).
Related errors
- Wrong number of arguments for invocation lscc(%s): received
- %s capability %s is required but not supported
- failed to parse collection config
- failed unmarshalling lscc read value into ChaincodeData
- application config does not exist for %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/f8cac14220d50f49.
Report an issue: GitHub.