hyperledger/fabric · error
signer must be the same as the one referenced in the header
Error message
signer must be the same as the one referenced in the header
What it means
CreateSignedTx compares the serialized signer identity with the Creator in the proposal's SignatureHeader and rejects mismatched identities. The transaction must be signed by the same identity that originally created the proposal; a different signer would produce an invalid transaction.
Source
Thrown at protoutil/txutils.go:175
// the original payload
pPayl, err := UnmarshalChaincodeProposalPayload(proposal.Payload)
if err != nil {
return nil, err
}
// check that the signer is the same that is referenced in the header
signerBytes, err := signer.Serialize()
if err != nil {
return nil, err
}
shdr, err := UnmarshalSignatureHeader(hdr.SignatureHeader)
if err != nil {
return nil, err
}
if !bytes.Equal(signerBytes, shdr.Creator) {
return nil, errors.New("signer must be the same as the one referenced in the header")
}
// ensure that all actions are bitwise equal and that they are successful
var a1 []byte
for n, r := range resps {
if r.Response.Status < 200 || r.Response.Status >= 400 {
return nil, errors.Errorf("proposal response was not successful, error code %d, msg %s", r.Response.Status, r.Response.Message)
}
if n == 0 {
a1 = r.Payload
continue
}
if !bytes.Equal(a1, r.Payload) {
return nil, errors.Errorf("ProposalResponsePayloads do not match (base64): '%s' vs '%s'",
b64.StdEncoding.EncodeToString(r.Payload), b64.StdEncoding.EncodeToString(a1))
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Sign the transaction with the same identity that created the proposal (pass the original creator's Signer)
- If a different identity must sign, regenerate the proposal with that identity instead of reusing
- Verify the MSP identity configuration matches the one used at proposal creation
- In tests, construct proposal and signature with the same signer helper
Example fix
// before otherSigner, _ := adminMSP.GetDefaultSigningIdentity() env, err := protoutil.CreateSignedTx(proposal, otherSigner, resps...) // proposal made by user // after userSigner, err := userMSP.GetDefaultSigningIdentity() // same identity as proposal creator env, err := protoutil.CreateSignedTx(proposal, userSigner, resps...)
Defensive patterns
Strategy: validation
Validate before calling
func verifySignerMatchesProposal(signer protoutil.Signer, prop *peer.Proposal) error {
shdr := &common.SignatureHeader{}
if err := proto.Unmarshal(prop.Header, shdr); err != nil {
return err
}
signerBytes, err := signer.Serialize()
if err != nil {
return err
}
if !bytes.Equal(signerBytes, shdr.Creator) {
return fmt.Errorf("signer does not match proposal creator")
}
return nil
} Try / catch
if err := verifySignerMatchesProposal(signer, proposal); err != nil {
return nil, err
}
tx, err := protoutil.CreateSignedTx(proposal, signer, resps...) Prevention
- Keep the proposal and its signer in the same context/session object
- Never reuse proposals across users or identities
- Compare identity serialization if switching between MSP implementations
When it happens
Trigger: Calling CreateSignedTx with a Signer whose serialized identity (creator bytes) differs from proposal.Header.SignatureHeader.Creator — e.g. a second client instance, a different MSP principal, or a proposal reused across users.
Common situations: Multi-user applications mixing up identities; proposals deserialized and re-signed by a gateway/admin identity; tests reusing a proposal captured from another signer; identity serialization differences across MSP versions/peers.
Related errors
- failed signing Request
- signer is required when creating a signed transaction
- failed unmarshaling identity %s
- could not create a signed Deliver SeekInfo message, somethin
- Chaincode %s with given certificate hash %v belongs to a dif
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/909187053f961cad.
Report an issue: GitHub.