rathole-org/rathole · error

Missing tls config

Error message

Missing tls config

What it means

The rustls transport requires TLS settings. In `new` (src/transport/rustls.rs:95), `config.tls.as_ref().ok_or_else(...)` fails when no tls section exists in TransportConfig, returning this error. Both the client connector and server acceptor are built from this same tls config, so it is mandatory.

Solutions

  1. Add the `[transport.tls]` section with certificate/key (server) and hostname/trusted_root (client).
  2. If TLS is not desired, change transport type to plain tcp.
  3. Ensure the correct config file is being loaded for the intended role (client vs server).
  4. Check the README/example configs for rustls-specific key expectations (PEM formats).

Example fix

# before
[transport]
type = "tls"

# after
[transport]
type = "tls"
[transport.tls]
hostname = "example.com"
cert = "server-cert.pem"
key = "server-key.pem"
Defensive patterns

Strategy: validation

Validate before calling

let raw = std::fs::read_to_string(config_path)?;
let cfg: toml::Value = toml::from_str(&raw)?;
if cfg.get("transport").and_then(|t| t.get("tls")).is_none() {
    anyhow::bail!("rustls transport requires [transport.tls] in config");
}

Prevention

When it happens

Trigger: Selecting the rustls-based tls transport while `[transport.tls]` is absent from the config file.

Common situations: Switching transport implementations (native-tls ↔ rustls features) and assuming config is optional; using a plain-TCP example config with a TLS transport type; stripping the tls section during templating/secret-injection that failed.

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/3d026e242b35aa7e. Report an issue: GitHub.

Appendix: source

Thrown at src/transport/rustls.rs:95

    Ok(Some(
        ClientConfig::builder()
            .with_root_certificates(root_certs)
            .with_no_client_auth(),
    ))
}

#[async_trait]
impl Transport for TlsTransport {
    type Acceptor = TcpListener;
    type RawStream = TcpStream;
    type Stream = TlsStream<TcpStream>;

    fn new(config: &TransportConfig) -> Result<Self> {
        let tcp = TcpTransport::new(config)?;
        let config = config
            .tls
            .as_ref()
            .ok_or_else(|| anyhow!("Missing tls config"))?;

        let connector = load_client_config(config)
            .unwrap()
            .map(|c| Arc::new(c).into());
        let tls_acceptor = load_server_config(config)
            .unwrap()
            .map(|c| Arc::new(c).into());

        Ok(TlsTransport {
            tcp,
            config: config.clone(),
            connector,
            tls_acceptor,
        })
    }

    fn hint(conn: &Self::Stream, opt: SocketOpts) {
        opt.apply(conn.get_ref().0);

View on GitHub (pinned to a292f7ed54)