hyperledger/fabric · error · VSCCEndorsementPolicyError
invalid key for the collection of chaincode %s:%s; expected
Error message
invalid key for the collection of chaincode %s:%s; expected '%s', received '%s'
What it means
During LSCC (lifecycle system chaincode) validation, VSCC expects exactly two writes in the lscc rwset for a deploy: the chaincode definition and the collection configuration, keyed via privdata.BuildCollectionKVSKey(chaincodeName). This error means the key of the second write does not equal the expected '~collection<name>' key format. It indicates a malformed or hand-crafted lscc writeset, so the transaction is rejected as a policy error.
Source
Thrown at core/handlers/validation/builtin/v12/validation_logic.go:390
/********************************************/
// there can only be one or two writes
if len(lsccrwset.Writes) > 2 {
return policyErr(fmt.Errorf("LSCC can only issue one or two putState upon deploy"))
}
/**********************************************************/
/* security check 0.b - validation of the collection data */
/**********************************************************/
var collectionsConfigArg []byte
if len(lsccArgs) > 5 {
collectionsConfigArg = lsccArgs[5]
}
var collectionsConfigLedger []byte
if len(lsccrwset.Writes) == 2 {
key := privdata.BuildCollectionKVSKey(cdRWSet.Name)
if lsccrwset.Writes[1].Key != key {
return policyErr(fmt.Errorf("invalid key for the collection of chaincode %s:%s; expected '%s', received '%s'",
cdRWSet.Name, cdRWSet.Version, key, lsccrwset.Writes[1].Key))
}
collectionsConfigLedger = lsccrwset.Writes[1].Value
}
if !bytes.Equal(collectionsConfigArg, collectionsConfigLedger) {
return policyErr(fmt.Errorf("collection configuration arguments supplied for chaincode %s:%s do not match the configuration in the lscc writeset",
cdRWSet.Name, cdRWSet.Version))
}
channelState, err := vscc.stateFetcher.FetchState()
if err != nil {
return &commonerrors.VSCCExecutionFailureError{Err: fmt.Errorf("failed obtaining query executor: %v", err)}
}
defer channelState.Done()
state := &state{channelState}View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure the deploy goes through the standard SDK/peer instantiate path (chaincode.Invoke with type 'deploy' plus the collection configuration argument) so lscc itself builds the collection key with privdata.BuildCollectionKVSKey.
- Verify the lscc rwset contains exactly two writes with the collection config as the second write under key '~collection<chaincodeName>'.
- Check that the chaincode name used in the collection config matches the name in the chaincode data (cdRWSet.Name); a mismatch yields a different expected key.
- If running custom validation, confirm peer/VSCC versions match across the network (v1.2 validation logic vs older key formats).
Example fix
// before: custom tool writes collection config under wrong key lsccrwset.Writes[1].Key = chaincodeName + "~collection" // after: build the key the way lscc does lsccrwset.Writes[1].Key = privdata.BuildCollectionKVSKey(cdRWSet.Name)
Defensive patterns
Strategy: validation
Validate before calling
// Before submitting an lscc deploy writeset, assert the collection key matches
import "github.com/hyperledger/fabric/core/common/privdata"
func validateCollectionKey(chaincodeName string, writes []*kvrwset.KVWrite) error {
if len(writes) != 2 {
return fmt.Errorf("expected 2 lscc writes, got %d", len(writes))
}
expected := privdata.BuildCollectionKVSKey(chaincodeName)
if writes[1].Key != expected {
return fmt.Errorf("collection key mismatch: expected %q, got %q", expected, writes[1].Key)
}
return nil
} Prevention
- Always deploy collections via the standard peer instantiate/upgrade command or SDK lifecycle APIs, never by hand-writing lscc writesets
- Use privdata.BuildCollectionKVSKey to compute collection keys whenever constructing or inspecting lscc writes
- Keep all peers at the same Fabric version so the collection key scheme is consistent across the network
When it happens
Trigger: Deploying (instantiating) a chaincode with collections where the lscc rwset's second write key was not generated by privdata.BuildCollectionKVSKey(cdRWSet.Name) — e.g. the proposal's collectionConfig was marshaled under a wrong or legacy key format, the write order differs (collection config is not Writes[1]), or a malicious/buggy client submits a forged lscc writeset.
Common situations: Custom or modified lifecycle tooling writing collection config directly to lscc instead of going through the standard instantiate/invoke path; chaincode names containing characters that make the collection key mismatch; clients targeting a different Fabric version whose key scheme changed; forged transactions caught by endorsement-policy validation.
Related errors
- collection configuration arguments supplied for chaincode %s
- collection data should not exist for chaincode %s:%s
- GetChaincodeDeploymentSpec error %s
- VSCC error: invocation of lscc(%s) does not have appropriate
- unexpected chaincode spec type: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/0622ec3027854509.
Report an issue: GitHub.