EpicGames/lore · error · anyhow::Error

gRPC internal TLS is partially configured: cert=

Error message

gRPC internal TLS is partially configured: cert={}, key={}, cert_chain={}. Provide all three or none

What it means

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.

Solutions

  1. Provide all three files (server cert, private key, client CA cert chain) in the internal TLS config, or remove all three.
  2. Check secret mounts/volumes so that all three files actually exist at the configured paths.
  3. Compare the config keys against the current struct fields after upgrades to catch renamed/missing entries.

Example fix

// before (config)
[grpc_internal.tls]
cert_file = "/certs/server.pem"
pkey_file = "/certs/server.key"   // cert_chain missing -> partial
// after
[grpc_internal.tls]
cert_file = "/certs/server.pem"
pkey_file = "/certs/server.key"
cert_chain_file = "/certs/client-ca.pem"
Defensive patterns

Strategy: validation

Validate before calling

let parts = (tls.cert.as_deref(), tls.key.as_deref(), tls.chain.as_deref());
let set = parts.iter().filter(|p| p.is_some()).count();
if set != 0 && set != 3 {
    return Err("internal gRPC TLS needs all of cert, key, cert_chain or none".into());
}

Try / catch

if let Err(e) = GrpcInternalServer::with_tls_config(...) {
    if e.to_string().contains("partially configured") {
        eprintln!("fix internal TLS: provide cert, key AND cert_chain, or none");
    }
    return Err(e);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13). Data as JSON: /api/errors/69c8868fbe351918. Report an issue: GitHub.

Appendix: source

Thrown at lore-server/src/grpc/grpc_internal_server.rs:140

    ) -> anyhow::Result<GrpcInternalServerBuilder<WantsHttp2Config>> {
        let tls_config = match (cert_path, key_path, cert_chain_path) {
            (Some(cert_path), Some(key_path), Some(cert_chain_path)) => {
                info!("Loading TLS certs - cert: {cert_path:?} key: {key_path:?}");
                let identity =
                    Identity::from_pem(std::fs::read(cert_path)?, std::fs::read(key_path)?);

                info!("Using CA cert: {cert_chain_path:?}");
                let ca_cert = std::fs::read(cert_chain_path)?;

                Some(
                    ServerTlsConfig::new()
                        .identity(identity)
                        .client_ca_root(Certificate::from_pem(ca_cert)),
                )
            }
            (None, None, None) => None,
            (cert, key, chain) => {
                return Err(anyhow!(
                    "gRPC internal TLS is partially configured: cert={}, key={}, cert_chain={}. \
                     Provide all three or none",
                    cert.is_some(),
                    key.is_some(),
                    chain.is_some(),
                ));
            }
        };

        Ok(GrpcInternalServerBuilder(WantsHttp2Config {
            local_immutable_store: self.0.local_immutable_store,
            immutable_store: self.0.immutable_store,
            mutable_store: self.0.mutable_store,
            notification_sender: self.0.notification_sender,
            hook_dispatcher: self.0.hook_dispatcher,
            environment: self.0.environment,
            tls_config,
        }))

View on GitHub (pinned to 074eb0b0d1)