{"record":{"id":"5d439e68e15dc1a7","repo":"hyperledger/fabric","slug":"proposalresponsepayloads-do-not-match-base64","errorCode":null,"errorMessage":"ProposalResponsePayloads do not match (base64): '%s' vs '%s'","messagePattern":"ProposalResponsePayloads do not match \\(base64\\): '(.+?)' vs '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"protoutil/txutils.go","lineNumber":191,"sourceCode":"\n\tif !bytes.Equal(signerBytes, shdr.Creator) {\n\t\treturn nil, errors.New(\"signer must be the same as the one referenced in the header\")\n\t}\n\n\t// ensure that all actions are bitwise equal and that they are successful\n\tvar a1 []byte\n\tfor n, r := range resps {\n\t\tif r.Response.Status < 200 || r.Response.Status >= 400 {\n\t\t\treturn nil, errors.Errorf(\"proposal response was not successful, error code %d, msg %s\", r.Response.Status, r.Response.Message)\n\t\t}\n\n\t\tif n == 0 {\n\t\t\ta1 = r.Payload\n\t\t\tcontinue\n\t\t}\n\n\t\tif !bytes.Equal(a1, r.Payload) {\n\t\t\treturn nil, errors.Errorf(\"ProposalResponsePayloads do not match (base64): '%s' vs '%s'\",\n\t\t\t\tb64.StdEncoding.EncodeToString(r.Payload), b64.StdEncoding.EncodeToString(a1))\n\t\t}\n\t}\n\n\t// fill endorsements according to their uniqueness\n\tendorsersUsed := make(map[string]struct{})\n\tvar endorsements []*peer.Endorsement\n\tfor _, r := range resps {\n\t\tif r.Endorsement == nil {\n\t\t\tcontinue\n\t\t}\n\t\tkey := string(r.Endorsement.Endorser)\n\t\tif _, used := endorsersUsed[key]; used {\n\t\t\tcontinue\n\t\t}\n\t\tendorsements = append(endorsements, r.Endorsement)\n\t\tendorsersUsed[key] = struct{}{}\n\t}","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/protoutil/txutils.go#L173-L209","documentation":"When multiple proposal responses are supplied, CreateSignedTx requires all ProposalResponsePayloads to be bitwise identical so a deterministic transaction can be built. If any payload differs (different read-write set, different result), the error reports both payloads base64-encoded for comparison.","triggerScenarios":"Endorsers returned divergent results for the same proposal — different read/write sets, nondeterministic chaincode (map iteration, timestamps, randomness), or queries executed at different block heights.","commonSituations":"Nondeterministic chaincode using Go map iteration order or time.Now(); endorsers on different ledger states (one behind); using responses collected at different times or from proposals with differing nonces; CouchDB vs LevelDB divergence.","solutions":["Make the chaincode deterministic: no randomness, map-range-order dependence, wall-clock time, or external calls in transactions","Ensure all endorsers are at the same ledger height before endorsement (retry or wait for sync)","Collect responses from a single proposal instance (same txid/nonce) rather than mixing proposals","Diff the base64 payloads in the error to identify the divergent field"],"exampleFix":"// before\n// chaincode nondeterminism\nfor k := range stateMap { results[k] = stateMap[k] } // map order varies per peer\n// after\nkeys := make([]string, 0, len(stateMap))\nfor k := range stateMap { keys = append(keys, k) }\nsort.Strings(keys)\nfor _, k := range keys { results[k] = stateMap[k] }","handlingStrategy":"validation","validationCode":"func payloadsIdentical(resps []*peer.ProposalResponse) error {\n    if len(resps) < 2 { return nil }\n    first := resps[0].Payload\n    for _, r := range resps[1:] {\n        if !bytes.Equal(first, r.Payload) {\n            return fmt.Errorf(\"divergent endorsement payloads\")\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := payloadsIdentical(resps); err != nil {\n    // endorsers disagree: resync peers or fix chaincode determinism, then retry\n    return nil, err\n}\ntx, err := protoutil.CreateSignedTx(proposal, signer, resps...)","preventionTips":["Write deterministic chaincode: no map-iteration order, no time.Now(), no randomness","Ensure endorsing peers are in sync (same block height) before endorsing","Always use responses from a single proposal instance"],"tags":["endorsement","determinism","hyperledger-fabric","chaincode"],"backgroundTag":"proposal-response-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"}