{"record":{"id":"637f1d1cfcd9c219","repo":"hyperledger/fabric","slug":"invalid-txid-got-s-expected-s","errorCode":null,"errorMessage":"invalid txid. got [%s], expected [%s]","messagePattern":"invalid txid\\. got \\[(.+?)\\], expected \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"protoutil/proputils.go","lineNumber":401,"sourceCode":"\n// ComputeTxID computes TxID as the Hash computed\n// over the concatenation of nonce and creator.\nfunc ComputeTxID(nonce, creator []byte) string {\n\t// TODO: Get the Hash function to be used from\n\t// channel configuration\n\thasher := sha256.New()\n\thasher.Write(nonce)\n\thasher.Write(creator)\n\treturn hex.EncodeToString(hasher.Sum(nil))\n}\n\n// CheckTxID checks that txid is equal to the Hash computed\n// over the concatenation of nonce and creator.\nfunc CheckTxID(txid string, nonce, creator []byte) error {\n\tcomputedTxID := ComputeTxID(nonce, creator)\n\n\tif txid != computedTxID {\n\t\treturn errors.Errorf(\"invalid txid. got [%s], expected [%s]\", txid, computedTxID)\n\t}\n\n\treturn nil\n}\n\n// InvokedChaincodeName takes the proposal bytes of a SignedProposal, and unpacks it all the way down,\n// until either an error is encountered, or the chaincode name is found. This is useful primarily\n// for chaincodes which wish to know the chaincode name originally invoked, in order to deny cc2cc\n// invocations (or, perhaps to deny direct invocations and require cc2cc).\nfunc InvokedChaincodeName(proposalBytes []byte) (string, error) {\n\tproposal := &peer.Proposal{}\n\terr := proto.Unmarshal(proposalBytes, proposal)\n\tif err != nil {\n\t\treturn \"\", errors.WithMessage(err, \"could not unmarshal proposal\")\n\t}\n\n\tproposalPayload := &peer.ChaincodeProposalPayload{}\n\terr = proto.Unmarshal(proposal.Payload, proposalPayload)","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/protoutil/proputils.go#L383-L419","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ntxid := uuid.New().String()\n\n// after\nnonce, err := crypto.GetRandomNonce()\nif err != nil {\n    return err\n}\ncreator := signerCert.Raw\ntxid := protoutil.ComputeTxID(nonce, creator)","handlingStrategy":"validation","validationCode":"if txid != protoutil.ComputeTxID(nonce, creator) {\n    return fmt.Errorf(\"txid %s does not match nonce/creator hash\", txid)\n}\n// proceed only when equal","typeGuard":null,"tryCatchPattern":"if err := protoutil.CheckTxID(txid, nonce, creator); err != nil {\n    return fmt.Errorf(\"rejecting transaction: %w (recompute txid from nonce+creator)\", err)\n}","preventionTips":["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."],"tags":["fabric","txid","validation","transaction"],"backgroundTag":"txid-mismatch","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}