hyperledger/fabric · error

chaincode event chaincode id does not match chaincode action

Error message

chaincode event chaincode id does not match chaincode action chaincode id

What it means

After successfully unmarshalling the chaincode event, VSCC checks that ccEvent.ChaincodeId equals the invoked chaincode's name (ccID from the header extension). A mismatch means the event claims a different chaincode than the action's chaincode, indicating forged or misattributed events, so the transaction is invalid with TxValidationCode_INVALID_OTHER_REASON.

Source

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

	}
	// sanity check on ccver
	if ccVer == "" {
		err = errors.New("invalid chaincode version")
		logger.Errorf("%+v", err)
		return peer.TxValidationCode_INVALID_OTHER_REASON, err
	}

	var wrNamespace []string
	alwaysEnforceOriginalNamespace := v.cr.Capabilities().V1_2Validation()
	if alwaysEnforceOriginalNamespace {
		wrNamespace = append(wrNamespace, ccID)
		if respPayload.Events != nil {
			ccEvent := &peer.ChaincodeEvent{}
			if err = proto.Unmarshal(respPayload.Events, ccEvent); err != nil {
				return peer.TxValidationCode_INVALID_OTHER_REASON, errors.Wrapf(err, "invalid chaincode event")
			}
			if ccEvent.ChaincodeId != ccID {
				return peer.TxValidationCode_INVALID_OTHER_REASON, errors.Errorf("chaincode event chaincode id does not match chaincode action chaincode id")
			}
		}
	}

	namespaces := make(map[string]struct{})
	for _, ns := range txRWSet.NsRwSets {
		// check to make sure there is no duplicate namespace in txRWSet
		if _, ok := namespaces[ns.NameSpace]; ok {
			return peer.TxValidationCode_ILLEGAL_WRITESET, errors.Errorf("duplicate namespace '%s' in txRWSet", ns.NameSpace)
		}
		namespaces[ns.NameSpace] = struct{}{}

		if !v.txWritesToNamespace(ns) {
			continue
		}

		// Check to make sure we did not already populate this chaincode
		// name to avoid checking the same namespace twice

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Fix the chaincode so events are created only via stub.SetEvent, which sets ChaincodeId to the current chaincode.
  2. Remove or correct any manually populated ChaincodeId in event structs inside the chaincode.
  3. Audit shared helper/SDK code that constructs ChaincodeEvent objects for the whole network.

Example fix

// before
evt := &peer.ChaincodeEvent{ChaincodeId: "othercc", EventName: "e"}
// after
stub.SetEvent("e", payload) // shim fills ChaincodeId automatically
Defensive patterns

Strategy: validation

Validate before calling

if ccEvent.ChaincodeId != ccID {
    return fmt.Errorf("event chaincode id %q does not match action chaincode id %q", ccEvent.ChaincodeId, ccID)
}

Type guard

func eventMatchesChaincode(evt *peer.ChaincodeEvent, expectedID string) bool {
	return evt != nil && evt.ChaincodeId == expectedID
}

Try / catch

if ccEvent.ChaincodeId != ccID {
    logger.Warnf("tx rejected: event chaincode id mismatch (%s != %s)", ccEvent.ChaincodeId, ccID)
    return peer.TxValidationCode_INVALID_OTHER_REASON, nil
}

Prevention

When it happens

Trigger: A chaincode (or payload tamperer) emits an event whose ChaincodeId field differs from the chaincode that produced the action — e.g. copying event structs from another chaincode's stub, or manually constructing events with a wrong ChaincodeId.

Common situations: Chaincode code that hardcodes another chaincode's ID in its event struct; generic event-emitting helper libraries setting an incorrect ID; deliberate tampering blocked by validation.

Related errors


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