hyperledger/fabric · error

chaincode %s:%s/%s didn't match %s:%s/%s in lscc

Error message

chaincode %s:%s/%s didn't match %s:%s/%s in lscc

What it means

VSCC validation checks that the version of the chaincode recorded in the transaction matches the version lscc (lifecycle system chaincode) currently holds on the channel. When the invoked namespace equals the transaction's chaincode but its version differs from the lscc-recorded version, the transaction is marked EXPIRED_CHAINCODE. This prevents committing transactions produced against stale chaincode deployments.

Source

Thrown at core/committer/txvalidator/v14/vscc_validator.go:204

		if writesToNonInvokableSCC {
			return peer.TxValidationCode_ILLEGAL_WRITESET,
				errors.Errorf("chaincode %s attempted to write to the namespace of a system chaincode that cannot be invoked", ccID)
		}

		// validate *EACH* read write set according to its chaincode's endorsement policy
		for _, ns := range wrNamespace {
			// Get latest chaincode version, vscc and validate policy
			txcc, vscc, policy, err := v.GetInfoForValidate(chdr, ns)
			if err != nil {
				logger.Errorf("GetInfoForValidate for txId = %s returned error: %+v", chdr.TxId, err)
				return peer.TxValidationCode_INVALID_OTHER_REASON, err
			}

			// if the namespace corresponds to the cc that was originally
			// invoked, we check that the version of the cc that was
			// invoked corresponds to the version that lscc has returned
			if ns == ccID && txcc.ChaincodeVersion != ccVer {
				err = errors.Errorf("chaincode %s:%s/%s didn't match %s:%s/%s in lscc", ccID, ccVer, chdr.ChannelId, txcc.ChaincodeName, txcc.ChaincodeVersion, chdr.ChannelId)
				logger.Errorf("%+v", err)
				return peer.TxValidationCode_EXPIRED_CHAINCODE, err
			}

			// do VSCC validation
			ctx := &Context{
				Seq:       seq,
				Envelope:  envBytes,
				Block:     block,
				TxID:      chdr.TxId,
				Channel:   chdr.ChannelId,
				Namespace: ns,
				Policy:    policy,
				VSCCName:  vscc.ChaincodeName,
			}
			if err = v.VSCCValidateTxForCC(ctx); err != nil {
				switch err.(type) {
				case *commonerrors.VSCCEndorsementPolicyError:

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Re-submit the transaction after the chaincode upgrade completes so it is endorsed against the current version
  2. Coordinate upgrades to avoid in-flight transactions (drain/stop traffic during upgrade)
  3. Ensure all endorsing peers have the same chaincode version installed and instantiated
  4. Check lscc output (peer chaincode list) to confirm current version and align client expectations

Example fix

// before: resubmitting stale tx after upgrade
const tx = oldSignedTx; await gateway.submit(tx);
// after: create a fresh proposal against the current version
const tx = await contract.createTransaction('move'); await tx.submit(args);
Defensive patterns

Strategy: retry

Validate before calling

// check current instantiated version before submitting
const deployed = await channel.queryInstantiatedChaincodes();
if (deployed.find(c => c.name === ccName).version !== expectedVersion) { /* abort or re-endorse */ }

Type guard

function matchesDeployedVersion(ccData, name, ver) {
  return ccData && ccData.name === name && ccData.version === ver;
}

Try / catch

try { await tx.submit(); } catch (e) {
  if (String(e).includes('EXPIRED_CHAINCODE') || String(e).includes("didn't match")) { /* re-create proposal against current version and retry once */ }
}

Prevention

When it happens

Trigger: A transaction endorsed against chaincode version X is validated after the chaincode was upgraded to version Y via lscc (txcc.ChaincodeVersion != ccVer). Happens when a tx is signed/in flight during a chaincode upgrade.

Common situations: Chaincode upgrade performed while in-flight transactions are still being validated; endorsement by a peer running an old chaincode version; SDK retrying stale transactions after an upgrade.

Related errors


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