{"record":{"id":"fac5dd6732ea20ea","repo":"hyperledger/fabric","slug":"duplicate-transaction-found-s-creator-x","errorCode":null,"errorMessage":"duplicate transaction found [%s]. Creator [%x]","messagePattern":"duplicate transaction found \\[(.+?)\\]\\. Creator \\[%x\\]","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/endorser/endorser.go","lineNumber":284,"sourceCode":"\t\t// ignore uniqueness checks; also, chainless proposals are not validated using the policies\n\t\t// of the chain since by definition there is no chain; they are validated against the local\n\t\t// MSP of the peer instead by the call to ValidateUnpackProposal above\n\t\treturn nil\n\t}\n\n\t// labels that provide context for failure metrics\n\tmeterLabels := []string{\n\t\t\"channel\", up.ChannelHeader.ChannelId,\n\t\t\"chaincode\", up.ChaincodeName,\n\t}\n\n\t// Here we handle uniqueness check and ACLs for proposals targeting a chain\n\t// Notice that ValidateProposalMessage has already verified that TxID is computed properly\n\tif _, err = e.Support.GetTransactionByID(up.ChannelHeader.ChannelId, up.ChannelHeader.TxId); err == nil {\n\t\t// increment failure due to duplicate transactions. Useful for catching replay attacks in\n\t\t// addition to benign retries\n\t\te.Metrics.DuplicateTxsFailure.With(meterLabels...).Add(1)\n\t\treturn errors.Errorf(\"duplicate transaction found [%s]. Creator [%x]\", up.ChannelHeader.TxId, up.SignatureHeader.Creator)\n\t}\n\n\t// check ACL only for application chaincodes; ACLs\n\t// for system chaincodes are checked elsewhere\n\tif !e.Support.IsSysCC(up.ChaincodeName) {\n\t\t// check that the proposal complies with the Channel's writers\n\t\tif err = e.Support.CheckACL(up.ChannelHeader.ChannelId, up.SignedProposal); err != nil {\n\t\t\te.Metrics.ProposalACLCheckFailed.With(meterLabels...).Add(1)\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ProcessProposal process the Proposal\n// Errors related to the proposal itself are returned with an error that results in a grpc error.\n// Errors related to proposal processing (either infrastructure errors or chaincode errors) are returned with a nil error,","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/endorser/endorser.go#L266-L302","documentation":"preProcess performs a uniqueness check: if GetTransactionByID finds the proposal's TxId already committed on the channel, the transaction is a duplicate (possible replay or benign retry) and the proposal is rejected with the txid and creator identity in the message.","triggerScenarios":"Submitting a proposal whose computed TxId matches an already-validated/committed transaction — e.g. resubmitting the exact same signed proposal with same nonce and creator.","commonSituations":"Client retry logic resending the same signed proposal after a timeout; replay-attack attempts; SDK reusing a stale proposal/nonce after a failed commit; gateway double-submits.","solutions":["Generate a fresh nonce and recompute TxId (new signature) before resubmitting","Check the transaction status first; if already committed successfully, do not resubmit","Use idempotent client-side request tracking so retries create new proposals"],"exampleFix":"// before\nresubmit(sameSignedProposal) // same nonce/txid\n// after\nnonce := make([]byte, 24)\nrand.Read(nonce)\ntxid := computeTxID(creator, nonce) // re-sign proposal with new nonce","handlingStrategy":"retry","validationCode":"if _, err := q.GetTransactionByID(ch, txid); err == nil {\n    return errors.New(\"txid already exists: regenerate nonce before resubmit\")\n}","typeGuard":null,"tryCatchPattern":"resp, err := endorser.ProcessProposal(ctx, prop)\nif err != nil && strings.Contains(err.Error(), \"duplicate transaction found\") {\n    // regenerate nonce, rebuild txid, re-sign, then retry once\n    prop = newSignedProposal(creator, freshNonce())\n    resp, err = endorser.ProcessProposal(ctx, prop)\n}","preventionTips":["Generate a fresh nonce and TxId for every submission attempt","Check transaction status via qscc before retrying after timeouts","Never reuse a signed proposal for retries"],"tags":["endorser","duplicate-transaction","replay","txid"],"backgroundTag":"duplicate-transaction-found","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"}