hyperledger/fabric · error

expected Version '%s' does not match passed Version '%s'

Error message

expected Version '%s' does not match passed Version '%s'

What it means

This error is thrown by ChaincodeParameters.Equal in the lifecycle package when comparing an existing (expected) chaincode definition against a newly passed one, and the EndorsementInfo.Version field differs. It exists so that an approval/commit attempt which redefines a chaincode with a different version than the already-committed definition is rejected with a precise field-level message.

Source

Thrown at core/chaincode/lifecycle/lifecycle.go:126

// or adding fields will cause opaque checks to fail.
type ChaincodeLocalPackage struct {
	PackageID string
}

// ChaincodeParameters are the parts of the chaincode definition which are serialized
// as values in the statedb.  It is expected that any instance will have no nil fields once initialized.
// WARNING: This structure is serialized/deserialized from the DB, re-ordering or adding fields
// will cause opaque checks to fail.
type ChaincodeParameters struct {
	EndorsementInfo *lb.ChaincodeEndorsementInfo
	ValidationInfo  *lb.ChaincodeValidationInfo
	Collections     *pb.CollectionConfigPackage
}

func (cp *ChaincodeParameters) Equal(ocp *ChaincodeParameters) error {
	switch {
	case cp.EndorsementInfo.Version != ocp.EndorsementInfo.Version:
		return errors.Errorf("expected Version '%s' does not match passed Version '%s'", cp.EndorsementInfo.Version, ocp.EndorsementInfo.Version)
	case cp.EndorsementInfo.EndorsementPlugin != ocp.EndorsementInfo.EndorsementPlugin:
		return errors.Errorf("expected EndorsementPlugin '%s' does not match passed EndorsementPlugin '%s'", cp.EndorsementInfo.EndorsementPlugin, ocp.EndorsementInfo.EndorsementPlugin)
	case cp.EndorsementInfo.InitRequired != ocp.EndorsementInfo.InitRequired:
		return errors.Errorf("expected InitRequired '%t' does not match passed InitRequired '%t'", cp.EndorsementInfo.InitRequired, ocp.EndorsementInfo.InitRequired)
	case cp.ValidationInfo.ValidationPlugin != ocp.ValidationInfo.ValidationPlugin:
		return errors.Errorf("expected ValidationPlugin '%s' does not match passed ValidationPlugin '%s'", cp.ValidationInfo.ValidationPlugin, ocp.ValidationInfo.ValidationPlugin)
	case !bytes.Equal(cp.ValidationInfo.ValidationParameter, ocp.ValidationInfo.ValidationParameter):
		return errors.Errorf("expected ValidationParameter '%x' does not match passed ValidationParameter '%x'", cp.ValidationInfo.ValidationParameter, ocp.ValidationInfo.ValidationParameter)
	case !proto.Equal(cp.Collections, ocp.Collections):
		return errors.Errorf("Collections do not match")
	default:
	}
	return nil
}

// ChaincodeDefinition contains the chaincode parameters, as well as the sequence number of the definition.
// Note, it does not embed ChaincodeParameters so as not to complicate the serialization.  It is expected
// that any instance will have no nil fields once initialized.

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Use the exact version string that matches the currently committed definition, or increment the sequence number when intentionally changing the version
  2. Run 'peer lifecycle chaincode querycommitted' to see the committed version and align your approval with it
  3. Re-approve with the correct version so approved and committed definitions match

Example fix

// before
CommitChaincodeDefinition(name: 'mycc', version: '2.0', sequence: 1) // committed version is 1.0
// after
CommitChaincodeDefinition(name: 'mycc', version: '1.0', sequence: 1) // match committed version, or bump sequence to 2 for version 2.0
Defensive patterns

Strategy: validation

Validate before calling

committed, err := lifecycle.QueryChaincodeDefinition(chname, ccname, publicState)
if err == nil {
    if newDef.EndorsementInfo.Version != committed.EndorsementInfo.Version && newDef.Sequence == committed.Sequence {
        return fmt.Errorf("version %q differs from committed %q at same sequence", newDef.EndorsementInfo.Version, committed.EndorsementInfo.Version)
    }
}

Type guard

func sameVersion(a, b *lifecycle.ChaincodeParameters) bool {
    return a != nil && b != nil && a.EndorsementInfo.Version == b.EndorsementInfo.Version
}

Try / catch

if err := params.Equal(committedParams); err != nil {
    if strings.Contains(err.Error(), "does not match passed Version") {
        // re-query committed definition and re-approve with correct version or sequence+1
    }
    return err
}

Prevention

When it happens

Trigger: Calling CommitChaincodeDefinition or isAttemptToRedefine paths where the lifecycle ChaincodeParameters of the committed definition are compared via Equal and cp.EndorsementInfo.Version != ocp.EndorsementInfo.Version.

Common situations: Redeploying a chaincode with a bumped version while the same sequence number is already committed; peer state and approved definition out of sync; operator typos like 'v1.0' vs '1.0' when re-submitting a definition.

Related errors


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