hyperledger/fabric · error

nil ChaincodeId in ChaincodeAction

Error message

nil ChaincodeId in ChaincodeAction

What it means

VSCCValidateTx found respPayload.ChaincodeId nil: the ChaincodeAction inside the transaction's response payload lacks a ChaincodeID. VSCC uses it to cross-check the invoked chaincode's version and name against the header extension, so the transaction is marked invalid with TxValidationCode_INVALID_OTHER_REASON.

Source

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

	   3) does it write to any cc that cannot be invoked? */
	writesToLSCC := false
	writesToNonInvokableSCC := false
	respPayload, err := protoutil.GetActionFromEnvelope(envBytes)
	if err != nil {
		return peer.TxValidationCode_BAD_RESPONSE_PAYLOAD, errors.WithMessage(err, "GetActionFromEnvelope failed")
	}
	txRWSet := &rwsetutil.TxRwSet{}
	if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil {
		return peer.TxValidationCode_BAD_RWSET, errors.WithMessage(err, "txRWSet.FromProtoBytes failed")
	}

	// Verify the header extension and response payload contain the ChaincodeId
	if hdrExt.ChaincodeId == nil {
		return peer.TxValidationCode_INVALID_OTHER_REASON, errors.New("nil ChaincodeId in header extension")
	}

	if respPayload.ChaincodeId == nil {
		return peer.TxValidationCode_INVALID_OTHER_REASON, errors.New("nil ChaincodeId in ChaincodeAction")
	}

	// get name and version of the cc we invoked
	ccID := hdrExt.ChaincodeId.Name
	ccVer := respPayload.ChaincodeId.Version

	// sanity check on ccID
	if ccID == "" {
		err = errors.New("invalid chaincode ID")
		logger.Errorf("%+v", err)
		return peer.TxValidationCode_INVALID_OTHER_REASON, err
	}
	if ccID != respPayload.ChaincodeId.Name {
		err = errors.Errorf("inconsistent ccid info (%s/%s)", ccID, respPayload.ChaincodeId.Name)
		logger.Errorf("%+v", err)
		return peer.TxValidationCode_INVALID_OTHER_REASON, err
	}
	// sanity check on ccver

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure the chaincode runs on a matching Fabric shim/peer version so the peer populates ChaincodeAction.ChaincodeId correctly.
  2. Do not construct or modify proposal responses manually; collect endorsements via the SDK's transaction assembly.
  3. Verify chaincode deployment/invocation flow uses the standard proposal-response path instead of custom payload generation.

Example fix

// before: client assembles result payload manually
action := &peer.ChaincodeAction{Results: rwsetBytes}
// after: use SDK to assemble from real endorsement responses
tx, _ := transaction.New(proposalResponse)
// peer sets action.ChaincodeId itself
Defensive patterns

Strategy: validation

Validate before calling

action := &peer.ChaincodeAction{}
if err := proto.Unmarshal(respPayload.Results, action); err != nil || action.ChaincodeId == nil {
    return errors.New("ChaincodeAction must contain a ChaincodeId; use standard endorsement flow")
}

Type guard

func hasActionChaincodeId(resp *peer.ChaincodeAction) bool {
	return resp != nil && resp.ChaincodeId != nil
}

Try / catch

if respPayload.ChaincodeId == nil {
    logger.Warnf("tx rejected: nil ChaincodeId in ChaincodeAction")
    return peer.TxValidationCode_INVALID_OTHER_REASON, nil
}

Prevention

When it happens

Trigger: A chaincode (or the peer executing it) produced a ChaincodeAction whose Response.Payload (ChaincodeAction) has no chaincode_id set — e.g. chaincode results forged or rebuilt by a client, or responses injected/altered after endorsement.

Common situations: Hand-crafted proposal responses submitted directly to orderers; custom chaincode shim versions producing incomplete actions; tampering with endorsement payloads before collection.

Related errors


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