{"record":{"id":"d66c48ce3e069e64","repo":"hyperledger/fabric","slug":"consenter-s-d-has-invalid-certificates","errorCode":null,"errorMessage":"consenter %s:%d has invalid certificates","messagePattern":"consenter (.+?):(.+?) has invalid certificates","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/chain.go","lineNumber":1539,"sourceCode":"\t\t}\n\t\treturn nil\n\t}\n\n\t// create the dummy parameters for ComputeMembershipChanges\n\tc.raftMetadataLock.RLock()\n\tdummyOldBlockMetadata := proto.Clone(c.opts.BlockMetadata).(*etcdraft.BlockMetadata)\n\tc.raftMetadataLock.RUnlock()\n\n\tdummyOldConsentersMap := CreateConsentersMap(dummyOldBlockMetadata, oldMetadata)\n\tchanges, err := ComputeMembershipChanges(dummyOldBlockMetadata, dummyOldConsentersMap, newMetadata.GetConsenters())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// new config metadata was verified above. Additionally need to check new consenters for certificates expiration\n\tfor _, c := range changes.AddedNodes {\n\t\tif err := validateConsenterTLSCerts(c, verifyOpts, false); err != nil {\n\t\t\treturn errors.Wrapf(err, \"consenter %s:%d has invalid certificates\", c.GetHost(), c.GetPort())\n\t\t}\n\t}\n\n\tactive := c.ActiveNodes.Load().([]uint64)\n\tif changes.UnacceptableQuorumLoss(active) {\n\t\tc.logger.Debugf(\"%d out of %d nodes are alive - %+v\", len(active), len(dummyOldConsentersMap), active)\n\t\treturn errors.Errorf(\"%d out of %d nodes are alive, configuration will result in quorum loss\", len(active), len(dummyOldConsentersMap))\n\t}\n\n\treturn nil\n}\n\n// StatusReport returns the ConsensusRelation & Status\nfunc (c *Chain) StatusReport() (types.ConsensusRelation, types.Status) {\n\tc.statusReportMutex.Lock()\n\tdefer c.statusReportMutex.Unlock()\n\n\treturn c.consensusRelation, c.status","sourceCodeStart":1521,"sourceCodeEnd":1557,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/chain.go#L1521-L1557","documentation":"When a config update adds consenter nodes, each newly added node's TLS certificates are validated for expiration and trust against the verify options (orderer/consensus/etcdraft/chain.go:1539). This error wraps the validation failure (e.g. expired certificate or untrusted chain) for a specific host:port. The config update is rejected so a bad node never joins the raft cluster.","triggerScenarios":"A config update that adds a consenter whose TLS server or client certificate fails validateConsenterTLSCerts — expired cert, cert not yet valid, or no chain to a root CA in the verify options.","commonSituations":"Enrolling new orderer nodes with certificates that are already expired or issued by a non-configured CA; long-lived environments where node certs lapsed before joining; generating certs with a clock-skewed machine.","solutions":["Read the wrapped cause and re-issue fresh TLS certs for the named consenter","Sign the new node's certs with a CA present in Orderer.TLS.RootCAs","Update the channel config with the renewed certs and resubmit the update","Synchronize the new node's system clock before generating certs"],"exampleFix":"// before\nfabric-ca-client enroll -u https://admin:pw@ca:7054 --tls.certfiles old-ca.pem // cert from unconfigured/expired CA\n// after\nfabric-ca-client enroll -u https://admin:pw@ca:7054 --tls.certfiles config-rootca.pem // cert chaining to Orderer.TLS.RootCAs","handlingStrategy":"validation","validationCode":"for _, c := range changes.AddedNodes {\n    if err := validateConsenterTLSCerts(c, verifyOpts, false); err != nil {\n        return fmt.Errorf(\"pre-check failed for %s:%d: %w\", c.GetHost(), c.GetPort(), err)\n    }\n}","typeGuard":"func certsFresh(c *common.Consenter, now time.Time) bool {\n    cert, err := parseCert(c.GetServerTlsCert())\n    return err == nil && now.After(cert.NotBefore) && now.Before(cert.NotAfter)\n}","tryCatchPattern":"if err := submitConfigUpdate(cfg); err != nil {\n    if strings.Contains(err.Error(), \"has invalid certificates\") {\n        // re-enroll the named consenter with a CA in RootCAs and resubmit\n    }\n}","preventionTips":["Renew node certs before their expiry when adding them to a cluster","Use monitoring on certificate lifetimes for orderer nodes","Enroll new nodes only from CAs present in the channel config"],"tags":["raft","tls","certificate-expiration","consenter"],"backgroundTag":"invalid-consenter-tls-cert","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"}