{"record":{"id":"797502f8cb6132fc","repo":"stalwartlabs/stalwart","slug":"unwrap-tls-called-on-non-tls-acceptor","errorCode":null,"errorMessage":"unwrap_tls called on non-TLS acceptor","messagePattern":"unwrap_tls called on non-TLS acceptor","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/network/tls.rs","lineNumber":205,"sourceCode":"                }\n            },\n            _ => TcpAcceptorResult::Plain(stream),\n        }\n    }\n\n    pub fn is_tls(&self) -> bool {\n        matches!(self, TcpAcceptor::Tls { .. })\n    }\n}\n\nimpl<IO> TcpAcceptorResult<IO>\nwhere\n    IO: AsyncRead + AsyncWrite + Unpin,\n{\n    pub fn unwrap_tls(self) -> Accept<IO> {\n        match self {\n            TcpAcceptorResult::Tls(accept) => accept,\n            _ => panic!(\"unwrap_tls called on non-TLS acceptor\"),\n        }\n    }\n}\n\nimpl std::fmt::Debug for CertificateResolver {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"CertificateResolver\").finish()\n    }\n}\n","sourceCodeStart":187,"sourceCodeEnd":215,"githubUrl":"https://github.com/stalwartlabs/stalwart/blob/e96200385781a6a9995a8b839ac27d6c75a983ee/crates/common/src/network/tls.rs#L187-L215","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet tls_acceptor = result.unwrap_tls();\n// after\nlet tls_acceptor = match result {\n    TcpAcceptorResult::Tls(accept) => accept,\n    other => panic!(\"TLS expected but got non-TLS acceptor: {:?}\", other),\n};\n// or better: handle Tcp gracefully instead of panicking","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn is_tls(result: &TcpAcceptorResult<impl AsyncRead + AsyncWrite>) -> bool {\n    matches!(result, TcpAcceptorResult::Tls(_))\n}","tryCatchPattern":"match acceptor_result {\n    TcpAcceptorResult::Tls(accept) => { /* TLS path */ }\n    TcpAcceptorResult::Tcp(accept) => { /* plaintext fallback */ }\n    TcpAcceptorResult::Failed(e) => { /* log accept error */ }\n}","preventionTips":["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."],"tags":["tls","network","rust","panic"],"backgroundTag":"unsupported-operation","analyzedSha":"e96200385781a6a9995a8b839ac27d6c75a983ee","analyzedAt":"2026-09-06T22:07:17.982Z","contentChangedAt":"2026-09-06T22:07:17.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}