hyperledger/fabric · error

nil ChaincodeId in header extension

Error message

nil ChaincodeId in header extension

What it means

The v20 plugin dispatcher validates that both the header extension and the ChaincodeAction response payload carry a ChaincodeId before extracting name/version for validation. When the transaction's header extension has a nil ChaincodeId, the transaction is structurally malformed and is rejected with INVALID_OTHER_REASON. This guards against transactions that don't identify which chaincode they invoke.

Source

Thrown at core/committer/txvalidator/v20/plugindispatcher/dispatcher.go:130

	// get header extensions so we have the chaincode ID
	hdrExt, err := protoutil.UnmarshalChaincodeHeaderExtension(chdr.Extension)
	if err != nil {
		return peer.TxValidationCode_BAD_HEADER_EXTENSION, err
	}

	/* obtain the list of namespaces we're writing to */
	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_CHAINCODE, err
	}
	if ccID != respPayload.ChaincodeId.Name {
		err = errors.Errorf("inconsistent ccid info (%s/%s)", ccID, respPayload.ChaincodeId.Name)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Fix the client to always set ChaincodeId in the proposal header extension (use a maintained SDK)
  2. Trace the offending transaction via peer logs/txId and inspect the envelope with configtxlator/inspect tools
  3. Reject malformed proposals at the gateway/orderer before they reach blocks
  4. Update SDK/Fabric versions if a known serialization bug produced nil ChaincodeId

Example fix

// before: manually built proposal missing ChaincodeId
const hdrExt = new HeaderExt(); hdrExt.ChaincodeId = null;
// after
const hdrExt = new HeaderExt(); hdrExt.ChaincodeId = {name: 'mycc', version: '1.0'};
Defensive patterns

Strategy: validation

Validate before calling

// client-side pre-check before signing/submitting
if (!proposal.getHeader().getExtension().chaincodeId) throw new Error('missing ChaincodeId in header extension');

Type guard

function hasChaincodeId(hdrExt) {
  return !!hdrExt && !!hdrExt.chaincodeId && !!hdrExt.chaincodeId.name;
}

Try / catch

try { await gateway.submit(tx); } catch (e) {
  if (String(e).includes('nil ChaincodeId in header extension')) { /* rebuild proposal via SDK, do not retry same envelope */ }
}

Prevention

When it happens

Trigger: Dispatch (VSCC validation for the v20 tx validator plugin) parses a TxRWSet and inspects hdrExt.ChaincodeId — a proposal header extension without ChaincodeId reaches validation, e.g. a malformed or hand-crafted envelope.

Common situations: Buggy or low-level client SDK usage constructing proposals without ChaincodeId; malicious/fuzzed transaction submission; corrupted envelope bytes on the ordering path.

Related errors


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