{"record":{"id":"8961bfc7cd32f889","repo":"hyperledger/fabric","slug":"peer-tls-clientkey-file-and-peer-tls-clientcert-fi","errorCode":null,"errorMessage":"peer.tls.clientKey.file and peer.tls.clientCert.file must both be set or must both be empty","messagePattern":"peer\\.tls\\.clientKey\\.file and peer\\.tls\\.clientCert\\.file must both be set or must both be empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/peer/config.go","lineNumber":469,"sourceCode":"\t}\n\tif viper.IsSet(\"peer.maxSendMsgSize\") {\n\t\tserverConfig.MaxSendMsgSize = int(viper.GetInt32(\"peer.maxSendMsgSize\"))\n\t}\n\treturn serverConfig, nil\n}\n\n// GetClientCertificate returns the TLS certificate to use for gRPC client\n// connections\nfunc GetClientCertificate() (tls.Certificate, error) {\n\tcert := tls.Certificate{}\n\n\tkeyPath := viper.GetString(\"peer.tls.clientKey.file\")\n\tcertPath := viper.GetString(\"peer.tls.clientCert.file\")\n\n\tif keyPath != \"\" || certPath != \"\" {\n\t\t// need both keyPath and certPath to be set\n\t\tif keyPath == \"\" || certPath == \"\" {\n\t\t\treturn cert, errors.New(\"peer.tls.clientKey.file and \" +\n\t\t\t\t\"peer.tls.clientCert.file must both be set or must both be empty\")\n\t\t}\n\t\tkeyPath = config.GetPath(\"peer.tls.clientKey.file\")\n\t\tcertPath = config.GetPath(\"peer.tls.clientCert.file\")\n\n\t} else {\n\t\t// use the TLS server keypair\n\t\tkeyPath = viper.GetString(\"peer.tls.key.file\")\n\t\tcertPath = viper.GetString(\"peer.tls.cert.file\")\n\n\t\tif keyPath != \"\" || certPath != \"\" {\n\t\t\t// need both keyPath and certPath to be set\n\t\t\tif keyPath == \"\" || certPath == \"\" {\n\t\t\t\treturn cert, errors.New(\"peer.tls.key.file and \" +\n\t\t\t\t\t\"peer.tls.cert.file must both be set or must both be empty\")\n\t\t\t}\n\t\t\tkeyPath = config.GetPath(\"peer.tls.key.file\")\n\t\t\tcertPath = config.GetPath(\"peer.tls.cert.file\")","sourceCodeStart":451,"sourceCodeEnd":487,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/peer/config.go#L451-L487","documentation":"GetClientCertificate resolves the client key/cert pair used for mutual TLS. If exactly one of peer.tls.clientKey.file and peer.tls.clientCert.file is set (XOR condition), the configuration is invalid and this error is returned; both must be set together or both left empty.","triggerScenarios":"Calling GetClientCertificate when only one of peer.tls.clientKey.file / peer.tls.clientCert.file is non-empty in viper config (core.yaml or CORE_PEER_TLS_CLIENTKEY_FILE / CORE_PEER_TLS_CLIENTCERT_FILE env vars).","commonSituations":"Setting CORE_PEER_TLS_CLIENTKEY_FILE but forgetting CORE_PEER_TLS_CLIENTCERT_FILE (or vice versa) in docker-compose env; partial secret mount containing only one of the two files; copy-paste config from a non-TLS peer.","solutions":["Set both CORE_PEER_TLS_CLIENTKEY_FILE and CORE_PEER_TLS_CLIENTCERT_FILE (and the corresponding core.yaml keys) to valid paths.","Or unset/remove both keys if client TLS keypair is not needed.","Verify both files exist and are non-empty at the configured paths.","Check docker-compose/K8s env blocks so the pair is always set together."],"exampleFix":"// before (environment)\nCORE_PEER_TLS_CLIENTKEY_FILE=/etc/hyperledger/fabric/tls/client.key\n// (clientCert missing)\n// after\nCORE_PEER_TLS_CLIENTKEY_FILE=/etc/hyperledger/fabric/tls/client.key\nCORE_PEER_TLS_CLIENTCERT_FILE=/etc/hyperledger/fabric/tls/client.crt","handlingStrategy":"validation","validationCode":"keyPath := viper.GetString(\"peer.tls.clientKey.file\")\ncertPath := viper.GetString(\"peer.tls.clientCert.file\")\nif (keyPath == \"\") != (certPath == \"\") {\n  return errors.New(\"client key and client cert must both be set or both empty\")\n}","typeGuard":null,"tryCatchPattern":"cert, err := GetClientCertificate()\nif err != nil && strings.Contains(err.Error(), \"clientCert.file must both be set\") {\n  log.Fatalf(\"set both client key and cert TLS files: %v\", err)\n}","preventionTips":["Always set client key/cert as a pair","Lint paired env vars in deployment configs","Mount both files in the same secret"],"tags":["tls","config","mutual-tls","hyperledger-fabric"],"backgroundTag":"tls-key-cert-pair-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"}