rathole-org/rathole · error

Missing `pkcs12` or `pkcs12_password`

Error message

Missing `pkcs12` or `pkcs12_password`

What it means

The TLS transport is enabled and a `[transport.tls]` section exists, but on the server side either `pkcs12` (the certificate file) or `pkcs12_password` is missing. The validator requires BOTH fields via `pkcs12.as_ref().and(pkcs12_password.as_ref())` before the server can load its identity.

Solutions

  1. Add both `pkcs12 = "path/to/cert.p12"` and `pkcs12_password = "..."` under `[transport.tls]` on the server
  2. If you only have a PEM cert/key, convert it: `openssl pkcs12 -export -out cert.p12 -inkey key.pem -in cert.pem`
  3. Confirm the config is intended for a server — clients don't need pkcs12; check `is_server` matches your role section
  4. Verify the keys are inside `[transport.tls]`, not a sibling table

Example fix

# before
[transport.tls]
pkcs12 = "server.p12"

# after
[transport.tls]
pkcs12 = "server.p12"
pkcs12_password = "changeit"
Defensive patterns

Strategy: validation

Validate before calling

let raw: toml::Value = toml::from_str(&cfg)?;
let tls = &raw["transport"]["tls"];
let is_server = raw.get("server").is_some();
if is_server && (tls["pkcs12"].is_none() || tls["pkcs12_password"].is_none()) {
    return Err("server TLS config needs both pkcs12 and pkcs12_password".into());
}

Prevention

When it happens

Trigger: Running rathole in server mode with `transport.type = "tls"` where `[transport.tls]` defines only one of `pkcs12` or `pkcs12_password`, or neither; also when the keys are placed in the wrong table so they don't deserialize into `TlsConfig`.

Common situations: Server operators generate a certificate but forget the export password; they move the p12 file without updating the config; client-side configs mistakenly include server fields or omit them while the same config is reused for a server.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of rathole-org/rathole@a292f7ed54 (2026-09-07). Data as JSON: /api/errors/36856a32107ef004. Report an issue: GitHub.

Appendix: source

Thrown at src/config.rs:317

            .as_ref()
            .map_or(Ok(()), |u| match u.scheme() {
                "socks5" => Ok(()),
                "http" => Ok(()),
                _ => Err(anyhow!(format!("Unknown proxy scheme: {}", u.scheme()))),
            })?;
        match config.transport_type {
            TransportType::Tcp => Ok(()),
            TransportType::Tls => {
                let tls_config = config
                    .tls
                    .as_ref()
                    .ok_or_else(|| anyhow!("Missing TLS configuration"))?;
                if is_server {
                    tls_config
                        .pkcs12
                        .as_ref()
                        .and(tls_config.pkcs12_password.as_ref())
                        .ok_or_else(|| anyhow!("Missing `pkcs12` or `pkcs12_password`"))?;
                }
                Ok(())
            }
            TransportType::Noise => {
                // The check is done in transport
                Ok(())
            }
            TransportType::Websocket => Ok(()),
        }
    }

    pub async fn from_file(path: &Path) -> Result<Config> {
        let s: String = fs::read_to_string(path)
            .await
            .with_context(|| format!("Failed to read the config {:?}", path))?;
        Config::from_str(&s).with_context(|| {
            "Configuration is invalid. Please refer to the configuration specification."
        })

View on GitHub (pinned to a292f7ed54)