hyperledger/fabric · error

expected EndorsementPlugin '%s' does not match passed Endors

Error message

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

What it means

Thrown by ChaincodeParameters.Equal when the EndorsementPlugin field of the new chaincode definition differs from the committed one. Lifecycle forbids silently changing which endorsement plugin a chaincode uses between definitions at the same sequence.

Source

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

	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.
// WARNING: This structure is serialized/deserialized from the DB, re-ordering or adding fields
// will cause opaque checks to fail.

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Keep the EndorsementPlugin identical to the committed definition, or increase the sequence number to intentionally change it
  2. Verify the plugin name spelling against the peer's core.yaml endorsementPlugins configuration
  3. Re-approve the definition on all orgs with a consistent EndorsementPlugin value

Example fix

// before
EndorsementPlugin: 'my-custom-escc', sequence: 1 // committed uses 'escc'
// after
EndorsementPlugin: 'escc', sequence: 1 // or sequence: 2 to legitimately change plugins
Defensive patterns

Strategy: validation

Validate before calling

committed, err := lifecycle.QueryChaincodeDefinition(chname, ccname, publicState)
if err == nil && newDef.EndorsementInfo.EndorsementPlugin != committed.EndorsementInfo.EndorsementPlugin && newDef.Sequence == committed.Sequence {
    return fmt.Errorf("endorsement plugin change requires sequence bump")
}

Type guard

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

Try / catch

if err := params.Equal(committedParams); err != nil {
    var expected string
    if strings.Contains(err.Error(), "EndorsementPlugin") {
        // fall back to committed plugin name or bump sequence
    }
    return err
}

Prevention

When it happens

Trigger: Committing or redefining a chaincode whose EndorsementInfo.EndorsementPlugin differs from the already-committed definition; comparison invoked from isAttemptToRedefine or CommitChaincodeDefinition.

Common situations: Switching from the default 'escc' to a custom endorsement plugin without bumping sequence; one org approved with 'escc' while another approved a different plugin name and the reconciled definition differs.

Related errors


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