{"record":{"id":"69c8868fbe351918","repo":"EpicGames/lore","slug":"grpc-internal-tls-is-partially-configured-cert-key-cert","errorCode":null,"errorMessage":"gRPC internal TLS is partially configured: cert={}, key={}, cert_chain={}. Provide all three or none","messagePattern":"gRPC internal TLS is partially configured: cert=(.+?), key=(.+?), cert_chain=(.+?)\\. Provide all three or none","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"lore-server/src/grpc/grpc_internal_server.rs","lineNumber":140,"sourceCode":"    ) -> anyhow::Result<GrpcInternalServerBuilder<WantsHttp2Config>> {\n        let tls_config = match (cert_path, key_path, cert_chain_path) {\n            (Some(cert_path), Some(key_path), Some(cert_chain_path)) => {\n                info!(\"Loading TLS certs - cert: {cert_path:?} key: {key_path:?}\");\n                let identity =\n                    Identity::from_pem(std::fs::read(cert_path)?, std::fs::read(key_path)?);\n\n                info!(\"Using CA cert: {cert_chain_path:?}\");\n                let ca_cert = std::fs::read(cert_chain_path)?;\n\n                Some(\n                    ServerTlsConfig::new()\n                        .identity(identity)\n                        .client_ca_root(Certificate::from_pem(ca_cert)),\n                )\n            }\n            (None, None, None) => None,\n            (cert, key, chain) => {\n                return Err(anyhow!(\n                    \"gRPC internal TLS is partially configured: cert={}, key={}, cert_chain={}. \\\n                     Provide all three or none\",\n                    cert.is_some(),\n                    key.is_some(),\n                    chain.is_some(),\n                ));\n            }\n        };\n\n        Ok(GrpcInternalServerBuilder(WantsHttp2Config {\n            local_immutable_store: self.0.local_immutable_store,\n            immutable_store: self.0.immutable_store,\n            mutable_store: self.0.mutable_store,\n            notification_sender: self.0.notification_sender,\n            hook_dispatcher: self.0.hook_dispatcher,\n            environment: self.0.environment,\n            tls_config,\n        }))","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-server/src/grpc/grpc_internal_server.rs#L122-L158","documentation":"GrpcInternalServer::with_tls_config validates that gRPC internal TLS is configured all-or-nothing: server cert, private key, and client CA cert chain. If exactly one or two of the three are set, it returns this error listing which ones are present. Partial TLS would produce a server that cannot authenticate peers correctly.","triggerScenarios":"Calling with_tls_config where internal_tls settings provide cert/key/cert_chain in a partial combination, e.g. only cert and key without cert_chain, or only cert_chain.","commonSituations":"Operators configure mTLS but forget the client CA chain; a secret-mount only partially populated so one file is missing and treated as unset; config templates that omit optional fields independently; upgrade changed field names so one key no longer maps.","solutions":["Provide all three files (server cert, private key, client CA cert chain) in the internal TLS config, or remove all three.","Check secret mounts/volumes so that all three files actually exist at the configured paths.","Compare the config keys against the current struct fields after upgrades to catch renamed/missing entries."],"exampleFix":"// before (config)\n[grpc_internal.tls]\ncert_file = \"/certs/server.pem\"\npkey_file = \"/certs/server.key\"   // cert_chain missing -> partial\n// after\n[grpc_internal.tls]\ncert_file = \"/certs/server.pem\"\npkey_file = \"/certs/server.key\"\ncert_chain_file = \"/certs/client-ca.pem\"","handlingStrategy":"validation","validationCode":"let parts = (tls.cert.as_deref(), tls.key.as_deref(), tls.chain.as_deref());\nlet set = parts.iter().filter(|p| p.is_some()).count();\nif set != 0 && set != 3 {\n    return Err(\"internal gRPC TLS needs all of cert, key, cert_chain or none\".into());\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = GrpcInternalServer::with_tls_config(...) {\n    if e.to_string().contains(\"partially configured\") {\n        eprintln!(\"fix internal TLS: provide cert, key AND cert_chain, or none\");\n    }\n    return Err(e);\n}","preventionTips":["Keep the three TLS files in one secret and mount them atomically.","Templated configs: emit all-or-none blocks, not independently optional keys.","Add a config linter that checks TLS field presence as a group."],"tags":["grpc","tls","mtls","config"],"backgroundTag":"conflicting-config-options","analyzedSha":"074eb0b0d1194c997d7cf28b55519e3e197b3e23","analyzedAt":"2026-09-13T09:00:57.509Z","contentChangedAt":"2026-09-13T09:00:57.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}