hyperledger/fabric · error
invalid txid. got [%s], expected [%s]
Error message
invalid txid. got [%s], expected [%s]
What it means
CheckTxID verifies that a transaction ID equals ComputeTxID(nonce, creator), i.e. the SHA256 hash of the nonce concatenated with the creator's serialized identity. If the supplied txid differs from the computed hash, the proposal/transaction is rejected because its binding to nonce and creator cannot be trusted.
Source
Thrown at protoutil/proputils.go:401
// ComputeTxID computes TxID as the Hash computed
// over the concatenation of nonce and creator.
func ComputeTxID(nonce, creator []byte) string {
// TODO: Get the Hash function to be used from
// channel configuration
hasher := sha256.New()
hasher.Write(nonce)
hasher.Write(creator)
return hex.EncodeToString(hasher.Sum(nil))
}
// CheckTxID checks that txid is equal to the Hash computed
// over the concatenation of nonce and creator.
func CheckTxID(txid string, nonce, creator []byte) error {
computedTxID := ComputeTxID(nonce, creator)
if txid != computedTxID {
return errors.Errorf("invalid txid. got [%s], expected [%s]", txid, computedTxID)
}
return nil
}
// InvokedChaincodeName takes the proposal bytes of a SignedProposal, and unpacks it all the way down,
// until either an error is encountered, or the chaincode name is found. This is useful primarily
// for chaincodes which wish to know the chaincode name originally invoked, in order to deny cc2cc
// invocations (or, perhaps to deny direct invocations and require cc2cc).
func InvokedChaincodeName(proposalBytes []byte) (string, error) {
proposal := &peer.Proposal{}
err := proto.Unmarshal(proposalBytes, proposal)
if err != nil {
return "", errors.WithMessage(err, "could not unmarshal proposal")
}
proposalPayload := &peer.ChaincodeProposalPayload{}
err = proto.Unmarshal(proposal.Payload, proposalPayload)View on GitHub (pinned to 2736b63f8f)
Solutions
- Regenerate the txid with protoutil.ComputeTxID(nonce, creator) using exactly the same nonce and creator bytes placed in the envelope's SignatureHeader.
- Ensure the creator bytes in the SignatureHeader are identical to the bytes hashed into the txid (same msp/identity serialization).
- Do not reuse a txid across proposals: compute a fresh nonce and txid per transaction.
- If using an SDK, let it compute the txid rather than supplying one manually.
Example fix
// before
txid := uuid.New().String()
// after
nonce, err := crypto.GetRandomNonce()
if err != nil {
return err
}
creator := signerCert.Raw
txid := protoutil.ComputeTxID(nonce, creator) Defensive patterns
Strategy: validation
Validate before calling
if txid != protoutil.ComputeTxID(nonce, creator) {
return fmt.Errorf("txid %s does not match nonce/creator hash", txid)
}
// proceed only when equal Try / catch
if err := protoutil.CheckTxID(txid, nonce, creator); err != nil {
return fmt.Errorf("rejecting transaction: %w (recompute txid from nonce+creator)", err)
} Prevention
- Compute txid exclusively via protoutil.ComputeTxID with the same nonce and creator placed in the SignatureHeader.
- Never reuse nonces or txids across transactions; generate a fresh nonce per proposal.
- Keep the creator's serialized identity stable between txid computation and envelope signing (renewing certs invalidates pending txids).
- Add a round-trip test asserting CheckTxID passes for envelopes produced by your client.
When it happens
Trigger: ValidateTransaction or TestProposalTxID receives a txid that does not equal the hash of the given nonce+creator: the client generated the txid with different nonce/creator bytes, used a random string, hashed with a different algorithm/encoding, or reused a txid from another proposal.
Common situations: SDK-generated txids computed over a different identity serialization (e.g. after cert renewal); manually crafted envelopes in tests; chaincode clients that cache txids across retries with regenerated nonces; switching fabric SDK versions that changed txid computation.
Related errors
- Only Endorser Transactions are supported, provided type %d
- %s is mandatory and cannot be empty
- enrollment certificate isn't a valid PEM block
- failed to decode PEM block from %s
- could not create channel %s sub-group config
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/637f1d1cfcd9c219.
Report an issue: GitHub.