{"record":{"id":"99176f0d94b2fd3d","repo":"hyperledger/fabric","slug":"cannot-load-server-cert-for-consenter-s-d-s-99176f","errorCode":null,"errorMessage":"cannot load server cert for consenter %s:%d: %s","messagePattern":"cannot load server cert for consenter (.+?):(.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configtxgen/encoder/encoder.go","lineNumber":271,"sourceCode":"\t\t\tId:    consenter.ID,\n\t\t\tHost:  consenter.Host,\n\t\t\tPort:  consenter.Port,\n\t\t\tMspId: consenter.MSPID,\n\t\t}\n\t\t// Expect the user to set the config value for client/server certs or identity to the\n\t\t// path where they are persisted locally, then load these files to memory.\n\t\tif consenter.ClientTLSCert != \"\" {\n\t\t\tclientCert, err := os.ReadFile(consenter.ClientTLSCert)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot load client cert for consenter %s:%d: %s\", c.GetHost(), c.GetPort(), err)\n\t\t\t}\n\t\t\tc.ClientTlsCert = clientCert\n\t\t}\n\n\t\tif consenter.ServerTLSCert != \"\" {\n\t\t\tserverCert, err := os.ReadFile(consenter.ServerTLSCert)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot load server cert for consenter %s:%d: %s\", c.GetHost(), c.GetPort(), err)\n\t\t\t}\n\t\t\tc.ServerTlsCert = serverCert\n\t\t}\n\n\t\tif consenter.Identity != \"\" {\n\t\t\tidentity, err := os.ReadFile(consenter.Identity)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot load identity for consenter %s:%d: %s\", c.GetHost(), c.GetPort(), err)\n\t\t\t}\n\t\t\tc.Identity = identity\n\t\t}\n\n\t\tconsenterProtos = append(consenterProtos, c)\n\t}\n\treturn consenterProtos, nil\n}\n\n// NewConsortiumOrgGroup returns an org component of the channel configuration.  It defines the crypto material for the","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/internal/configtxgen/encoder/encoder.go#L253-L289","documentation":"Same mechanism as the client cert, but for the consenter's ServerTLSCert: consenterProtosFromConfig reads the server TLS certificate file from disk with os.ReadFile and embeds it in the consenter proto. A missing/unreadable file produces this error naming the consenter host:port, aborting BFT orderer group construction.","triggerScenarios":"NewOrdererGroup (OrdererType BFT) → consenterProtosFromConfig with a ConsenterMapping entry whose ServerTLSCert path is set but os.ReadFile fails (file missing, permission denied, wrong cwd).","commonSituations":"Cert generated under a different node name than referenced in configtx.yaml, incomplete cryptogen output, or switching machines/environments (CI containers) where the crypto-config tree was not copied.","solutions":["Read the wrapped OS error to distinguish missing vs permission problems","ls/verify the ServerTLSCert path for the failing consenter host:port exists and is readable","Regenerate crypto material (cryptogen generate) if the tls directory is absent","Use absolute paths or ensure configtxgen runs from the config's expected working directory"],"exampleFix":"// before\n// ServerTLSCert: \"./tls/server.crt\" (file absent)\n// after\n// ServerTLSCert: \"/abs/path/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt\"","handlingStrategy":"validation","validationCode":"func checkServerCertReadable(path string) error {\n    b, err := os.ReadFile(path)\n    if err != nil { return err }\n    if !bytes.Contains(b, []byte(\"-----BEGIN CERTIFICATE-----\")) {\n        return errors.New(\"file is not a PEM certificate\")\n    }\n    return nil\n}","typeGuard":"func serverCertExists(consenter *genesisconfig.Consenter) bool {\n    if consenter.ServerTLSCert == \"\" { return true }\n    _, err := os.Stat(consenter.ServerTLSCert); return err == nil\n}","tryCatchPattern":"group, err := encoder.NewOrdererGroup(conf, caps)\nif err != nil && strings.Contains(err.Error(), \"cannot load server cert\") {\n    return fmt.Errorf(\"fix ServerTLSCert path for the named consenter: %w\", err)\n}","preventionTips":["Verify the tls/ directory exists for every orderer node before config generation","Match node names between crypto material and configtx.yaml entries","Copy the full crypto-config tree into CI containers rather than partial subsets"],"tags":["tls","filesystem","hyperledger-fabric","bft"],"backgroundTag":"certificate-file-not-found","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"}