stalwartlabs/stalwart · error
unwrap_tls called on non-TLS acceptor
Error message
unwrap_tls called on non-TLS acceptor
What it means
unwrap_tls is a convenience method on the result of accepting a connection (TcpAcceptorResult) that extracts the inner TLS acceptor, and it is only valid when the acceptor was actually configured for TLS. Calling it on a Tcp, non-Tls, or failed variant panics with this message. It exists so callers that know TLS is enabled can skip matching every variant.
Source
Thrown at crates/common/src/network/tls.rs:205
}
},
_ => TcpAcceptorResult::Plain(stream),
}
}
pub fn is_tls(&self) -> bool {
matches!(self, TcpAcceptor::Tls { .. })
}
}
impl<IO> TcpAcceptorResult<IO>
where
IO: AsyncRead + AsyncWrite + Unpin,
{
pub fn unwrap_tls(self) -> Accept<IO> {
match self {
TcpAcceptorResult::Tls(accept) => accept,
_ => panic!("unwrap_tls called on non-TLS acceptor"),
}
}
}
impl std::fmt::Debug for CertificateResolver {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("CertificateResolver").finish()
}
}
View on GitHub (pinned to e962003857)
Solutions
- Match on the TcpAcceptorResult variants instead of unwrapping: handle Tls, Tcp, and failed cases explicitly.
- If TLS is intended, fix the server configuration so the acceptor is created in TLS mode (valid certificate and key configured).
- Guard the call with an is_tls-style check or use the enum's accessor that returns Option instead of panicking.
Example fix
// before
let tls_acceptor = result.unwrap_tls();
// after
let tls_acceptor = match result {
TcpAcceptorResult::Tls(accept) => accept,
other => panic!("TLS expected but got non-TLS acceptor: {:?}", other),
};
// or better: handle Tcp gracefully instead of panicking Defensive patterns
Strategy: type-guard
Type guard
fn is_tls(result: &TcpAcceptorResult<impl AsyncRead + AsyncWrite>) -> bool {
matches!(result, TcpAcceptorResult::Tls(_))
} Try / catch
match acceptor_result {
TcpAcceptorResult::Tls(accept) => { /* TLS path */ }
TcpAcceptorResult::Tcp(accept) => { /* plaintext fallback */ }
TcpAcceptorResult::Failed(e) => { /* log accept error */ }
} Prevention
- Match all enum variants instead of calling unwrap_* methods.
- Keep TLS configuration and unwrap_tls call sites coupled — change them together.
- Add tests covering both TLS-enabled and TLS-disabled acceptor setups.
When it happens
Trigger: Calling `acceptor_result.unwrap_tls()` on a TcpAcceptorResult produced by an acceptor that is not in TLS mode — e.g. the server was configured without a TLS certificate so accepts return Tcp, or the code path calls unwrap_tls unconditionally instead of matching the variant first.
Common situations: A deployment switches TLS off (removes cert/key from config) while application code still assumes TLS and calls unwrap_tls; a code refactor changes acceptor setup so the TLS branch is no longer taken; unit tests constructing a plain TCP acceptor and then calling unwrap_tls.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Failed to load the platform certificate verifier
- Failed to build the TLS client configuration
- Unspecified
- Failed to read {yaml_path:?}
- Node id {node_id} exceeds {MAX_NODE_ID}, panicking to avoid
AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06).
Data as JSON: /api/errors/797502f8cb6132fc.
Report an issue: GitHub.