{"record":{"id":"459fd04f10410329","repo":"alibaba/nacos","slug":"client-certchainfile-or-certprivatekey-must-be-not","errorCode":null,"errorMessage":"client certChainFile or certPrivateKey must be not null","messagePattern":"client certChainFile or certPrivateKey must be not null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java","lineNumber":582,"sourceCode":"            }\n            if (StringUtils.isNotBlank(tlsConfig.getCiphers())) {\n                builder.ciphers(Arrays.asList(tlsConfig.getCiphers().split(\",\")));\n            }\n            if (tlsConfig.getTrustAll()) {\n                builder.trustManager(InsecureTrustManagerFactory.INSTANCE);\n            } else {\n                if (StringUtils.isBlank(tlsConfig.getTrustCollectionCertFile())) {\n                    throw new IllegalArgumentException(\"trustCollectionCertFile must be not null\");\n                }\n                Resource resource =\n                    resourceLoader.getResource(tlsConfig.getTrustCollectionCertFile());\n                builder.trustManager(resource.getInputStream());\n            }\n            \n            if (tlsConfig.getMutualAuthEnable()) {\n                if (StringUtils.isBlank(tlsConfig.getCertChainFile()) || StringUtils.isBlank(\n                    tlsConfig.getCertPrivateKey())) {\n                    throw new IllegalArgumentException(\n                        \"client certChainFile or certPrivateKey must be not null\");\n                }\n                Resource certChainFile = resourceLoader.getResource(tlsConfig.getCertChainFile());\n                Resource privateKey = resourceLoader.getResource(tlsConfig.getCertPrivateKey());\n                builder.keyManager(certChainFile.getInputStream(), privateKey.getInputStream(),\n                    tlsConfig.getCertPrivateKeyPassword());\n            }\n            return Optional.of(builder.build());\n        } catch (Exception e) {\n            throw new RuntimeException(\"Unable to build SslContext\", e);\n        }\n    }\n    \n    private ManagedChannelBuilder buildChannel(String serverIp, int port,\n        Optional<SslContext> sslContext) {\n        if (sslContext.isPresent()) {\n            return NettyChannelBuilder.forAddress(serverIp, port)\n                .negotiationType(NegotiationType.TLS)","sourceCodeStart":564,"sourceCodeEnd":600,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java#L564-L600","documentation":"GrpcClient.buildSslContext() requires both certChainFile and certPrivateKey when mutual TLS authentication is enabled. If either is blank it throws IllegalArgumentException before loading the key material, because mTLS cannot present a client identity without both halves.","triggerScenarios":"Constructing an RpcClientTlsConfig with mutualAuthEnable=true but leaving certChainFile or certPrivateKey unset/blank. The check runs during buildSslContext() at client start.","commonSituations":"Enabling mTLS from config but only providing the private key (or only the chain); property-key typos; environment-specific paths not set in the deployed environment; copying a config block that omitted the cert fields.","solutions":["Provide both tlsConfig.setCertChainFile() (the certificate chain PEM) and tlsConfig.setCertPrivateKey() (the private key PEM).","If a passphrase protects the key, also set setCertPrivateKeyPassword().","Verify both files are readable paths or classpath:/http URLs resolvable by the ResourceLoader.","If mTLS is not actually required, set mutualAuthEnable=false."],"exampleFix":"// before — mTLS on, only key supplied\nRpcClientTlsConfig tls = new RpcClientTlsConfig();\ntls.setEnableTls(true);\ntls.setMutualAuthEnable(true);\ntls.setCertPrivateKey(\"/etc/nacos/certs/client.key\");\n\n// after — both halves supplied\ntls.setCertChainFile(\"/etc/nacos/certs/client.crt\");\ntls.setCertPrivateKey(\"/etc/nacos/certs/client.key\");","handlingStrategy":"validation","validationCode":"static void validateMtls(RpcClientTlsConfig tls) {\n    if (Boolean.TRUE.equals(tls.getMutualAuthEnable())) {\n        if (isBlank(tls.getCertChainFile()) || isBlank(tls.getCertPrivateKey())) {\n            throw new IllegalArgumentException(\n                \"mTLS enabled: must set both certChainFile and certPrivateKey\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    client.start();\n} catch (RuntimeException re) {\n    if (re.getMessage().contains(\"certChainFile\")) {\n        // supply the missing cert chain / key, then retry\n    } else { throw re; }\n}","preventionTips":["Validate mTLS config before start(): both certChainFile and certPrivateKey must be set.","Include cert password handling if the key is encrypted.","Add a config validator to catch blank fields at deploy/test time."],"tags":["grpc","tls","ssl","mtls","config"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}