{"record":{"id":"9eb3e0594aa03cfb","repo":"hyperledger/fabric","slug":"node-id-mismatch","errorCode":null,"errorMessage":"node id mismatch","messagePattern":"node id mismatch","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/cluster/clusterservice.go","lineNumber":172,"sourceCode":"\t}\n\n\tfromIdentity := membership.MemberMapping[authReq.FromId]\n\tif fromIdentity == nil {\n\t\treturn nil, errors.Errorf(\"node %d is not member of channel %s\", authReq.FromId, authReq.Channel)\n\t}\n\n\ttoIdentity := membership.MemberMapping[authReq.ToId]\n\tif toIdentity == nil {\n\t\treturn nil, errors.Errorf(\"node %d is not member of channel %s\", authReq.ToId, authReq.Channel)\n\t}\n\n\tequal, err := CompareCertPublicKeys(toIdentity, s.NodeIdentity)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to compare cert public keys\")\n\t}\n\tif !equal {\n\t\ts.Logger.Debugf(\"node id mismatch for node %d, toIdentity: %s, s.NodeIdentity: %s\", authReq.FromId, string(toIdentity), string(s.NodeIdentity))\n\t\treturn nil, errors.Errorf(\"node id mismatch\")\n\t}\n\n\terr = VerifySignature(fromIdentity, SHA256Digest(msg), authReq.Signature)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"signature mismatch\")\n\t}\n\n\treturn authReq, nil\n}\n\nfunc (s *ClusterService) handleMessage(stream ClusterStepStream, addr string, exp *certificateExpirationCheck, channel string, sender uint64, streamID uint64) error {\n\trequest, err := stream.Recv()\n\tif err == io.EOF {\n\t\treturn err\n\t}\n\tif err != nil {\n\t\ts.Logger.Warningf(\"Stream read from %s failed: %v\", addr, err)\n\t\treturn err","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/clusterservice.go#L154-L190","documentation":"VerifyAuthRequest authenticates an incoming cluster Step request. After unwrapping the sender identity (toIdentity), it compares the certificate public key of that identity against the local node's configured identity (s.NodeIdentity). If CompareCertPublicKeys reports the keys are not equal, the request claims to come from a node other than the one this peer expects for that channel, so the RPC is rejected with 'node id mismatch'.","triggerScenarios":"ClusterService.Step receives an authReq whose FromId declares a sender, but the cert public key in the TLS/client context differs from s.NodeIdentity (the identity registered for the local node in the cluster RPC). This happens when the remote orderer presents the wrong TLS or client cert, or when the local node's TLS cert/identity was rotated or misconfigured so the configured NodeIdentity no longer matches what the peer actually authenticates with.","commonSituations":"A channel was formed on one set of orderer certs but an orderer was re-deployed with regenerated TLS certificates while the channel genesis/config still carries the old certs; crypto material copied between nodes so two orderers share/expect mismatched identities; org admin updated MSP or TLS CA but didn't update all orderers; typo in General.Cluster.ClientCertificate/ServerCertificate or in the channel's orderer endpoint/identity config.","solutions":["Regenerate/redeploy the orderer with the correct TLS certificate matching the identity registered in the channel configuration (crypto-material consistency across all orderers).","Compare the log line's toIdentity vs s.NodeIdentity (Debug level) and replace whichever side is stale — usually update the channel config's orderer TLS certs via a config update transaction.","Verify orderer.yaml General.TLS.Certificate and General.Cluster.* certificate paths point to the same cert generation as the channel's crypto material.","Ensure all orderers use certs issued by the same TLS CA recorded in the channel config; re-run the network bootstrap or perform an ordering-service config update if CAs changed.","Check for clock/genesis-block mismatch: confirm every node joined the same channel with the same genesis block so membership expectations align."],"exampleFix":"// before (orderer.yaml, node re-deployed with new certs but channel still expects old)\nGeneral:\n  TLS:\n    Certificate: /crypto/tls/new-server.crt\n// after — redeploy with the cert generation recorded in channel config, or update channel config:\n// configtxlator/ledger update: Orderer -> OrdererEndpoints + TLS certs => new-server.crt registered for this node","handlingStrategy":"validation","validationCode":"// Before deploying/starting the orderer, verify the node identity matches the TLS cert\nlocalCert := loadTLSCert(\"/crypto/tls/server.crt\")\nif !publicKeyEqual(localCert.PublicKey, nodeIdentityCert.PublicKey) {\n    return fmt.Errorf(\"TLS cert does not match configured NodeIdentity for this orderer\")\n}","typeGuard":"func identityMatches(tlsCert, nodeIdentity *x509.Certificate) bool {\n    if tlsCert == nil || nodeIdentity == nil { return false }\n    equal, err := CompareCertPublicKeys(tlsCert.Raw, nodeIdentity.Raw)\n    return err == nil && equal\n}","tryCatchPattern":null,"preventionTips":["Deploy all orderers from a single, consistent crypto-material generation","After any TLS cert rotation, perform a channel config update so every node's registered identity matches its new cert","Watch orderer logs for 'node id mismatch' at debug level during rollout and stop if they appear","Verify cert fingerprints across nodes before joining an orderer to a channel"],"tags":["hyperledger-fabric","orderer","tls","identity-mismatch","consensus"],"backgroundTag":"tls-certificate-identity-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"}