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 NoSuchCollectionError

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. 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.
  2. Diff the two CollectionConfigPackage definitions (signature, param JSON, required peers, member orgs, blockToLive, maxPeerCount) to find the mismatch.
  3. Use the same SDK/version to build both the argument and the writeset; avoid hand-constructing the collection config protobuf.
  4. 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

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


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/066d8e203075a514. Report an issue: GitHub.