hyperledger/fabric · error · VSCCEndorsementPolicyError
collection configuration arguments supplied for chaincode %s
Error message
collection configuration arguments supplied for chaincode %s:%s do not match the configuration in the lscc writeset
What it means
During deploy validation, VSCC compares the collection configuration bytes supplied in the instantiate call's collectionConfig argument with the collection config bytes stored in the lscc writeset (Writes[1].Value). This error means bytes.Equal of the two configurations failed. The proposal's collection config and what was actually written to lscc diverge, so the transaction is rejected.
Source
Thrown at core/handlers/validation/builtin/v12/validation_logic.go:398
/**********************************************************/
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}
// The following condition check added in v1.1 may not be needed as it is not possible to have the chaincodeName~collection key in
// the lscc namespace before a chaincode deploy. To avoid forks in v1.2, the following condition is retained.
if lsccFunc == lscc.DEPLOY {
colCriteria := privdata.CollectionCriteria{Channel: channelName, Namespace: cdRWSet.Name}
ccp, err := privdata.RetrieveCollectionConfigPackageFromState(colCriteria, state)
if err != nil {
// fail if we get any error other than NoSuchCollectionErrorView on GitHub (pinned to 2736b63f8f)
Solutions
- Regenerate the deploy/instantiate call so the exact same collections-config bytes are used in the proposal argument and the lscc write; re-instantiate with a consistent collectionConfig.
- Diff the two CollectionConfigPackage definitions (signature, param JSON, required peers, member orgs, blockToLive, maxPeerCount) to find the mismatch.
- Use the same SDK/version to build both the argument and the writeset; avoid hand-constructing the collection config protobuf.
- If protobuf field-ordering/marshaling is the cause, canonicalize the config (round-trip through the same proto message) before submitting.
Example fix
// before: proposal arg and writeset built from different files
proposalArgs := [[], [], mustRead("collections-old.json")]
writesetValue := mustMarshal(parse("collections-new.json"))
// after: single source of truth
configBytes := mustMarshal(parseCollectionConfig("collections.json"))
proposalArgs := [[], [], configBytes]
writesetValue := configBytes Defensive patterns
Strategy: validation
Validate before calling
// Client-side check: marshal the collection config once and reuse the same bytes
import "bytes"
func ensureMatchingConfig(arg []byte, ledger []byte) error {
if !bytes.Equal(arg, ledger) {
return fmt.Errorf("collectionConfig argument (%d bytes) differs from lscc writeset value (%d bytes)", len(arg), len(ledger))
}
return nil
} Prevention
- Pass the exact same collections-config file bytes to the instantiate/upgrade call and to anything that builds the writeset
- Do not edit the collections JSON between proposal creation and submission
- Round-trip the collection config through the same proto message (CollectionConfigPackage) once, then reuse the resulting bytes
- Pin one SDK version per release pipeline to avoid marshaling differences
When it happens
Trigger: Calling instantiate/invoke on lscc where the --collections-config argument passed to the peer/SDK differs byte-for-byte from the CollectionConfigPackage marshaled into the lscc writeset — e.g. two different JSON collection files, reordered protobuf fields causing different marshal output, or a custom client writing config bytes that differ from the proposal arg.
Common situations: Operator edits the collections JSON file between generating the proposal and submitting it; SDK normalizes/serializes collections differently than the peer (field ordering, defaults); protobuf marshaling instability across SDK versions; copy-paste of an older collection definition for a new chaincode version.
Related errors
- invalid key for the collection of chaincode %s:%s; expected
- 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/066d8e203075a514.
Report an issue: GitHub.