hyperledger/fabric · error
signature mismatch
Error message
signature mismatch
What it means
VerifyAuthRequest verifies that the incoming request payload was actually signed by the claimed sender. It computes SHA256Digest(msg) over the request bytes and calls VerifySignature with the sender's identity (fromIdentity) and authReq.Signature. If signature verification fails, the request may have been tampered with, the payload/signature got out of sync, or the signature was produced with a key that doesn't match fromIdentity.
Source
Thrown at orderer/common/cluster/clusterservice.go:177
}
toIdentity := membership.MemberMapping[authReq.ToId]
if toIdentity == nil {
return nil, errors.Errorf("node %d is not member of channel %s", authReq.ToId, authReq.Channel)
}
equal, err := CompareCertPublicKeys(toIdentity, s.NodeIdentity)
if err != nil {
return nil, errors.Wrap(err, "failed to compare cert public keys")
}
if !equal {
s.Logger.Debugf("node id mismatch for node %d, toIdentity: %s, s.NodeIdentity: %s", authReq.FromId, string(toIdentity), string(s.NodeIdentity))
return nil, errors.Errorf("node id mismatch")
}
err = VerifySignature(fromIdentity, SHA256Digest(msg), authReq.Signature)
if err != nil {
return nil, errors.Wrap(err, "signature mismatch")
}
return authReq, nil
}
func (s *ClusterService) handleMessage(stream ClusterStepStream, addr string, exp *certificateExpirationCheck, channel string, sender uint64, streamID uint64) error {
request, err := stream.Recv()
if err == io.EOF {
return err
}
if err != nil {
s.Logger.Warningf("Stream read from %s failed: %v", addr, err)
return err
}
if request == nil {
return errors.Errorf("request message is nil")
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Re-enroll/restart the sending node so its signing key matches the certificate distributed in the channel/MSP configuration.
- On the sender, confirm the request is signed over the exact serialized payload (SHA-256 digest) as received — regenerate the signature rather than reusing cached ones.
- Remove any intermediaries that modify bodies (disable LB/mesh body rewriting) between the two orderers.
- Ensure all Fabric orderer binaries are the same version so serialization and auth request formats agree.
- Compare the sender's certificate on disk with the one in the channel's MSP and update the MSP config if the cert was rotated.
Example fix
// before (sender caches signature from an older payload) req.Signature = cachedSig req.Payload = newPayload // after — always sign the exact bytes sent msg := payloadBytes digest := sha256.Sum256(msg) req.Payload = msg req.Signature = signer.Sign(digest[:])
Defensive patterns
Strategy: validation
Validate before calling
// Sender-side pre-flight: sign exactly the bytes being sent
digest := sha256.Sum256(payload)
sig, err := signer.Sign(digest[:])
if err != nil { return err }
// verify locally before sending
if err := VerifySignature(localIdentity, digest[:], sig); err != nil {
return fmt.Errorf("local signature would fail remote verification: %w", err)
} Try / catch
err := stepClient.Send(signedRequest)
if err != nil && strings.Contains(err.Error(), "signature mismatch") {
// re-sign with the current signer and retry once
signedRequest.Signature = resign(signedRequest.Payload)
err = stepClient.Send(signedRequest)
} Prevention
- Never reuse cached signatures across different payloads
- Re-enroll signing identities before distributing new certificates
- Keep Fabric binaries at the same version across the ordering service
- Avoid proxies that rewrite gRPC message bodies
When it happens
Trigger: ClusterService.Step receives a SignedRequest whose Signature field does not verify against the SHA-256 digest of its payload using the sender's enrolled client certificate — e.g. a client (or another orderer) signs with a different/stale key, the payload was modified after signing, or a proxy re-encoded the message bytes so the digest no longer matches.
Common situations: A replicated state issue where an orderer was re-enrolled (new key) but peers/services cache the old certificate; a manual or buggy client constructs Submit/Step requests without signing the exact serialized bytes; middleware (LB, service mesh) alters request bodies; Fabric binaries at mixed versions where request serialization differs.
Related errors
- empty signature bytes
- OrdererOrg config does not allow sub-groups
- Attempted to set the batch size preferred max bytes (%v) gre
- Attempted to set the batch timeout to a invalid value: %s
- Attempted to set the batch timeout to a non-positive value:
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/22a3287a145d349e.
Report an issue: GitHub.