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
- Use the exact version string that matches the currently committed definition, or increment the sequence number when intentionally changing the version
- Run 'peer lifecycle chaincode querycommitted' to see the committed version and align your approval with it
- 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
- Always run querycommitted before approving/committing to read the current version and sequence
- Keep version strings in a single source (CI variable) to avoid typos like v1.0 vs 1.0
- Bump the sequence number every time you intentionally change any definition field
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
- failed listing installed chaincodes
- failed to parse collection config
- [channel %s] failed to get chaincode container info for %s
- chaincode '%s' does not require initialization but called as
- private data APIs are not allowed in chaincode Init()
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/2801234fb69a55f3.
Report an issue: GitHub.