{"record":{"id":"066d8e203075a514","repo":"hyperledger/fabric","slug":"collection-configuration-arguments-supplied-for-ch","errorCode":null,"errorMessage":"collection configuration arguments supplied for chaincode %s:%s do not match the configuration in the lscc writeset","messagePattern":"collection configuration arguments supplied for chaincode (.+?):(.+?) do not match the configuration in the lscc writeset","errorType":"validation","errorClass":"VSCCEndorsementPolicyError","httpStatus":null,"severity":"error","filePath":"core/handlers/validation/builtin/v12/validation_logic.go","lineNumber":398,"sourceCode":"\t/**********************************************************/\n\tvar collectionsConfigArg []byte\n\tif len(lsccArgs) > 5 {\n\t\tcollectionsConfigArg = lsccArgs[5]\n\t}\n\n\tvar collectionsConfigLedger []byte\n\tif len(lsccrwset.Writes) == 2 {\n\t\tkey := privdata.BuildCollectionKVSKey(cdRWSet.Name)\n\t\tif lsccrwset.Writes[1].Key != key {\n\t\t\treturn policyErr(fmt.Errorf(\"invalid key for the collection of chaincode %s:%s; expected '%s', received '%s'\",\n\t\t\t\tcdRWSet.Name, cdRWSet.Version, key, lsccrwset.Writes[1].Key))\n\t\t}\n\n\t\tcollectionsConfigLedger = lsccrwset.Writes[1].Value\n\t}\n\n\tif !bytes.Equal(collectionsConfigArg, collectionsConfigLedger) {\n\t\treturn policyErr(fmt.Errorf(\"collection configuration arguments supplied for chaincode %s:%s do not match the configuration in the lscc writeset\",\n\t\t\tcdRWSet.Name, cdRWSet.Version))\n\t}\n\n\tchannelState, err := vscc.stateFetcher.FetchState()\n\tif err != nil {\n\t\treturn &commonerrors.VSCCExecutionFailureError{Err: fmt.Errorf(\"failed obtaining query executor: %v\", err)}\n\t}\n\tdefer channelState.Done()\n\n\tstate := &state{channelState}\n\n\t// The following condition check added in v1.1 may not be needed as it is not possible to have the chaincodeName~collection key in\n\t// the lscc namespace before a chaincode deploy. To avoid forks in v1.2, the following condition is retained.\n\tif lsccFunc == lscc.DEPLOY {\n\t\tcolCriteria := privdata.CollectionCriteria{Channel: channelName, Namespace: cdRWSet.Name}\n\t\tccp, err := privdata.RetrieveCollectionConfigPackageFromState(colCriteria, state)\n\t\tif err != nil {\n\t\t\t// fail if we get any error other than NoSuchCollectionError","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/handlers/validation/builtin/v12/validation_logic.go#L380-L416","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: proposal arg and writeset built from different files\nproposalArgs := [[], [], mustRead(\"collections-old.json\")]\nwritesetValue := mustMarshal(parse(\"collections-new.json\"))\n// after: single source of truth\nconfigBytes := mustMarshal(parseCollectionConfig(\"collections.json\"))\nproposalArgs := [[], [], configBytes]\nwritesetValue := configBytes","handlingStrategy":"validation","validationCode":"// Client-side check: marshal the collection config once and reuse the same bytes\nimport \"bytes\"\nfunc ensureMatchingConfig(arg []byte, ledger []byte) error {\n  if !bytes.Equal(arg, ledger) {\n    return fmt.Errorf(\"collectionConfig argument (%d bytes) differs from lscc writeset value (%d bytes)\", len(arg), len(ledger))\n  }\n  return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["fabric","vscc","lscc","collections","validation"],"backgroundTag":"collection-config-mismatch","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"}