transact-rs/sqlx · critical

one of the `runtime-*-native-tls` or `runtime-*-rustls` feat

Error message

one of the `runtime-*-native-tls` or `runtime-*-rustls` features must be enabled

What it means

sqlx's TLS connector() in sqlx-core/src/net/tls/mod.rs panics at runtime when a TLS connection is requested but the crate was compiled without any TLS backend feature. sqlx requires exactly one TLS implementation, selected via `runtime-*-native-tls` or `runtime-*-rustls` feature combinations; with neither `_tls-native-tls` nor `_tls-rustls` enabled, there is no connector to build.

Source

Thrown at sqlx-core/src/net/tls/mod.rs:86

#[cfg(feature = "_tls-native-tls")]
pub use self::tls_native_tls::NativeTlsConnector as TlsConnector;
#[cfg(all(feature = "_tls-rustls", not(feature = "_tls-native-tls")))]
pub use self::tls_rustls::RustlsConnector as TlsConnector;
#[cfg(not(any(feature = "_tls-native-tls", feature = "_tls-rustls")))]
#[derive(Debug, Clone)]
pub struct TlsConnector(std::convert::Infallible);

pub async fn connector(config: TlsConfig<'_>) -> crate::Result<TlsConnector> {
    #[cfg(feature = "_tls-native-tls")]
    return tls_native_tls::connector(config).await;

    #[cfg(all(feature = "_tls-rustls", not(feature = "_tls-native-tls")))]
    return tls_rustls::connector(config).await;

    #[cfg(not(any(feature = "_tls-native-tls", feature = "_tls-rustls")))]
    {
        _ = config;
        panic!("one of the `runtime-*-native-tls` or `runtime-*-rustls` features must be enabled")
    }
}

pub async fn handshake<S, Ws>(
    socket: S,
    hostname: &str,
    connector: &TlsConnector,
    with_socket: Ws,
) -> crate::Result<Ws::Output>
where
    S: Socket,
    Ws: WithSocket,
{
    #[cfg(feature = "_tls-native-tls")]
    return Ok(with_socket
        .with_socket(tls_native_tls::handshake(socket, hostname, connector).await?)
        .await);

View on GitHub (pinned to 03af8bcc57)

Solutions

  1. Enable a rustls-based combo: `sqlx = { features = ["runtime-tokio-rustls", "postgres"] }`.
  2. Or enable native-tls: `features = ["runtime-tokio-native-tls", "postgres"]`.
  3. Verify with `cargo tree -e features` (or `cargo metadata`) that one `_tls-*` feature is actually active; watch for other crates disabling default features and re-enabling only a bare runtime feature.
  4. If TLS is genuinely not needed, ensure the connection URL uses `sslmode=disable` so connector() is never invoked — but enabling a TLS feature is still the robust fix.

Example fix

// before (Cargo.toml)
sqlx = { version = "0.8", features = ["runtime-tokio", "postgres"] }

// after
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "postgres"] }
Defensive patterns

Strategy: validation

Validate before calling

// Verify a TLS backend is enabled at build time:
// Cargo.toml
[features]
default = ["runtime-tokio-rustls"]
// or assert in main.rs before connecting:
#[cfg(not(any(feature = "runtime-tokio-rustls", feature = "runtime-tokio-native-tls")))]
compile_error!("select a TLS runtime feature");

Prevention

When it happens

Trigger: Calling `sqlx::any::connect` / `PgPool::connect` etc. with a `postgres://...?sslmode=require` (or default-TLS) URL while the Cargo.toml enables only a runtime feature (e.g. `runtime-tokio`) without any `-native-tls`/`-rustls` suffix.

Common situations: Fresh project where the developer added `sqlx = { version = "...", features = ["runtime-tokio", "postgres"] }` and forgot the TLS feature; Docker release builds that trimmed features; upgrading sqlx and old feature names no longer mapping to TLS backends.

Understand the failure class

Related errors


AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03). Data as JSON: /api/errors/3f0313d1c293ac4d. Report an issue: GitHub.