{"record":{"id":"561bc0bbb54a6367","repo":"hyperledger/fabric","slug":"proposal-payload-cannot-be-nil","errorCode":null,"errorMessage":"proposal payload cannot be nil","messagePattern":"proposal payload cannot be nil","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/signature.go","lineNumber":73,"sourceCode":"\n\tif len(proposal.Header) == 0 {\n\t\treturn nil, errors.New(\"proposal header cannot be nil\")\n\t}\n\n\thdr := &asn1Header{}\n\n\tif _, err := asn1.Unmarshal(proposal.Header, hdr); err != nil {\n\t\treturn nil, errors.Wrap(err, \"bad header\")\n\t}\n\n\tblock.Header = &cb.BlockHeader{\n\t\tNumber:       hdr.Number.Uint64(),\n\t\tPreviousHash: hdr.PreviousHash,\n\t\tDataHash:     hdr.DataHash,\n\t}\n\n\tif len(proposal.Payload) == 0 {\n\t\treturn nil, errors.New(\"proposal payload cannot be nil\")\n\t}\n\n\ttuple := &ByteBufferTuple{}\n\tif err := tuple.FromBytes(proposal.Payload); err != nil {\n\t\treturn nil, errors.Wrap(err, \"bad payload and metadata tuple\")\n\t}\n\n\tif err := proto.Unmarshal(tuple.A, block.Data); err != nil {\n\t\treturn nil, errors.Wrap(err, \"bad payload\")\n\t}\n\n\tif err := proto.Unmarshal(tuple.B, block.Metadata); err != nil {\n\t\treturn nil, errors.Wrap(err, \"bad metadata\")\n\t}\n\treturn block, nil\n}\n\ntype asn1Header struct {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/signature.go#L55-L91","documentation":"ProposalToBlock requires the proposal's Payload field, which holds the serialized (payload, metadata) tuple of the block. An empty Payload means the block's data cannot be reconstructed, so conversion fails with this error after the header checks pass.","triggerScenarios":"VerifyProposal/SignProposal/RequestsFromProposal/Deliver invoked with a types.Proposal that has a valid Header but an empty or nil Payload byte slice — e.g. a proposal constructed only from a header or truncated during persistence.","commonSituations":"Corrupted proposal entries after unclean shutdown; integration code assembling Proposal structs manually and forgetting to set Payload; truncated records read from storage after disk issues.","solutions":["Ensure the code constructing types.Proposal populates both Header and Payload (Payload from the proposal's marshalled block data+metadata tuple).","Re-fetch the proposal by triggering node synchronization from other consenters.","Check disk health and ledger/WAL integrity; restore from backup if records are truncated.","Compare proposal bytes across consenters (signature verification logs) to locate the node with the incomplete proposal."],"exampleFix":"// before\nprop := types.Proposal{Header: headerBytes}\nblock, _ := ProposalToBlock(prop)\n\n// after\nprop := types.Proposal{Header: headerBytes, Payload: payloadBytes}\nblock, err := ProposalToBlock(prop)","handlingStrategy":"validation","validationCode":"if len(prop.Payload) == 0 {\n    return fmt.Errorf(\"proposal has no payload; cannot convert to block\")\n}\nblock, err := ProposalToBlock(prop)","typeGuard":"func hasProposalPayload(p *types.Proposal) bool {\n    return p != nil && len(p.Payload) > 0\n}","tryCatchPattern":"block, err := ProposalToBlock(prop)\nif err != nil && err.Error() == \"proposal payload cannot be nil\" {\n    // refetch proposal or trigger synchronization\n    return resync()\n}","preventionTips":["Always populate both Header and Payload when constructing proposals.","Check storage truncation after unclean shutdowns before processing records.","Persist proposal Header and Payload atomically.","Log proposal sizes at creation to detect truncation early."],"tags":["hyperledger-fabric","smartbft","proposal","malformed-data"],"backgroundTag":"proposal-payload-missing","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"}