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

  1. 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.
  2. Verify the lscc rwset contains exactly two writes with the collection config as the second write under key '~collection<chaincodeName>'.
  3. 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.
  4. 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

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


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