hyperledger/fabric · error

expected cc version %s, found %s

Error message

expected cc version %s, found %s

What it means

The validator compares the Version in the ChaincodeData produced by lscc against the Version in the submitted ChaincodeDeploymentSpec. If they differ, the write-set does not faithfully reflect the deployment spec and the transaction fails validation. This prevents an attacker from deploying one version while recording another on the ledger.

Source

Thrown at core/handlers/validation/builtin/v13/lscc_validation_logic.go:479

			return policyErr(fmt.Errorf("LSCC must issue at least one single putState upon deploy/upgrade"))
		}
		// the first key name must be the chaincode id provided in the deployment spec
		if lsccrwset.Writes[0].Key != cdsArgs.ChaincodeSpec.ChaincodeId.Name {
			return policyErr(fmt.Errorf("expected key %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, lsccrwset.Writes[0].Key))
		}
		// the value must be a ChaincodeData struct
		cdRWSet := &ccprovider.ChaincodeData{}
		err = proto.Unmarshal(lsccrwset.Writes[0].Value, cdRWSet)
		if err != nil {
			return policyErr(fmt.Errorf("unmarshalling of ChaincodeData failed, error %s", err))
		}
		// the chaincode name in the lsccwriteset must match the chaincode name in the deployment spec
		if cdRWSet.Name != cdsArgs.ChaincodeSpec.ChaincodeId.Name {
			return policyErr(fmt.Errorf("expected cc name %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, cdRWSet.Name))
		}
		// the chaincode version in the lsccwriteset must match the chaincode version in the deployment spec
		if cdRWSet.Version != cdsArgs.ChaincodeSpec.ChaincodeId.Version {
			return policyErr(fmt.Errorf("expected cc version %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Version, cdRWSet.Version))
		}
		// it must only write to 2 namespaces: LSCC's and the cc that we are deploying/upgrading
		for _, ns := range txRWSet.NsRwSets {
			if ns.NameSpace != "lscc" && ns.NameSpace != cdRWSet.Name && len(ns.KvRwSet.Writes) > 0 {
				return policyErr(fmt.Errorf("LSCC invocation is attempting to write to namespace %s", ns.NameSpace))
			}
		}

		logger.Debugf("Validating %s for cc %s version %s", lsccFunc, cdRWSet.Name, cdRWSet.Version)

		switch lsccFunc {
		case lscc.DEPLOY:

			/******************************************************************/
			/* security check 1 - cc not in the LCCC table of instantiated cc */
			/******************************************************************/
			if ccExistsOnLedger {
				return policyErr(fmt.Errorf("Chaincode %s is already instantiated", cdsArgs.ChaincodeSpec.ChaincodeId.Name))

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Regenerate the upgrade proposal with the correct, matching version in both ChaincodeSpec.ChaincodeId.Version and the lscc write value.
  2. If using custom code, construct ChaincodeData.Version from cds.ChaincodeSpec.ChaincodeId.Version.
  3. Discard cached signed proposals after changing the chaincode version.
  4. Verify the chaincode package/version used by install and instantiate steps is the same.

Example fix

// before
cd := &ccprovider.ChaincodeData{Name: name, Version: "1.0", ...}
// after
cd := &ccprovider.ChaincodeData{Name: cds.ChaincodeSpec.ChaincodeId.Name, Version: cds.ChaincodeSpec.ChaincodeId.Version, ...}
Defensive patterns

Strategy: validation

Validate before calling

// before submit: version in spec must equal version in lscc record
cd := &ccprovider.ChaincodeData{}
proto.Unmarshal(lsccWriteValue, cd)
if cd.Version != cds.ChaincodeSpec.ChaincodeId.Version {
    return fmt.Errorf("spec version %s != lscc record version %s", cds.ChaincodeSpec.ChaincodeId.Version, cd.Version)
}

Type guard

func versionMatches(cd *ccprovider.ChaincodeData, specVersion string) bool { return cd != nil && cd.Version == specVersion }

Try / catch

if err != nil && strings.Contains(err.Error(), "expected cc version") { /* rebuild proposal with matching version and resubmit */ }

Prevention

When it happens

Trigger: An upgrade transaction where the new version in ChaincodeSpec.ChaincodeId.Version does not equal the Version serialized into the lscc ChaincodeData write — e.g. a stale or mismatched proposal.

Common situations: Custom lifecycle tooling hard-coding version "1.0" while the spec says "2.0", reusing an old signed proposal after bumping the version, SDK builds the ChaincodeData from different metadata than the spec, replaying a previous upgrade transaction.

Related errors


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