{"record":{"id":"3191344f48b3895c","repo":"shadowsocks/shadowsocks-rust","slug":"https-outbound-proxy-requires-either-local-http-n","errorCode":null,"errorMessage":"HTTPS outbound proxy requires either `local-http-native-tls` or `local-http-rustls` feature","messagePattern":"HTTPS outbound proxy requires either `local-http-native-tls` or `local-http-rustls` feature","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks-service/src/net/outbound/tls.rs","lineNumber":30,"sourceCode":"\n#[cfg(any(feature = \"local-http-native-tls\", feature = \"local-http-rustls\"))]\nuse std::{\n    pin::Pin,\n    task::{self, Poll},\n};\n\n#[cfg(any(feature = \"local-http-native-tls\", feature = \"local-http-rustls\"))]\nuse pin_project::pin_project;\n#[cfg(any(feature = \"local-http-native-tls\", feature = \"local-http-rustls\"))]\nuse tokio::io::ReadBuf;\n\n#[cfg(any(feature = \"local-http-native-tls\", feature = \"local-http-rustls\"))]\nuse super::stream::OutboundProxyStream;\n\n/// Error helper for builds that disable both TLS backends.\n#[inline]\npub fn tls_unsupported<T>() -> io::Result<T> {\n    Err(io::Error::new(\n        io::ErrorKind::Unsupported,\n        \"HTTPS outbound proxy requires either `local-http-native-tls` or `local-http-rustls` feature\",\n    ))\n}\n\n/// TLS-wrapped outbound proxy stream.\n///\n/// The inner I/O object is a boxed [`OutboundProxyStream`]. Boxing is purely\n/// structural here: TLS libraries bake the inner type into their own\n/// generics, so without indirection every additional TLS hop in a chain\n/// would explode the type. There is **no** dynamic dispatch involved\n/// (the `Box<OutboundProxyStream>` is a sized concrete enum value, not\n/// `Box<dyn Trait>`).\n#[cfg(any(feature = \"local-http-native-tls\", feature = \"local-http-rustls\"))]\n#[pin_project(project = OutboundTlsStreamProj)]\npub enum OutboundTlsStream {\n    #[cfg(all(feature = \"local-http-native-tls\", not(feature = \"local-http-rustls\")))]\n    NativeTls(#[pin] tokio_native_tls::TlsStream<Box<OutboundProxyStream>>, bool),","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks-service/src/net/outbound/tls.rs#L12-L48","documentation":"HTTPS outbound proxy hops need a TLS backend; tls_unsupported is returned by tls_connect when the crate is built with neither `local-http-native-tls` nor `local-http-rustls`. The TLS layer is intentionally stubbed out so HTTPS hops cannot be established.","triggerScenarios":"Config contains an `https` outbound proxy hop while the build enables `local-http` but neither TLS backend feature; negotiate_hop calls tls_connect which hits tls_unsupported.","commonSituations":"Enabling only `local-http` (plain HTTP) and expecting HTTPS to work; feature matrix confusion between native-tls and rustls backends; minimal CI builds missing the TLS feature.","solutions":["Rebuild with a TLS backend: --features local-http-rustls (or local-http-native-tls)","Prefer the rustls backend for a pure-Rust build: cargo build --features local-http,local-http-rustls","Downgrade the hop to plain HTTP or SOCKS5 if TLS is not actually required"],"exampleFix":"// before\ncargo build --features local-http\n// after\ncargo build --features local-http,local-http-rustls","handlingStrategy":"validation","validationCode":"#[cfg(not(any(feature = \"local-http-native-tls\", feature = \"local-http-rustls\")))]\nif matches!(hop.kind, OutboundProxyKind::Https{..}) {\n    return Err(anyhow!(\"https hop needs a TLS backend feature enabled\"));\n}","typeGuard":"fn is_https_kind(k: &OutboundProxyKind) -> bool { matches!(k, OutboundProxyKind::Https{..}) }","tryCatchPattern":"if let Err(e) = tls_connect(stream, domain).await {\n    if e.kind() == io::ErrorKind::Unsupported {\n        eprintln!(\"enable local-http-native-tls or local-http-rustls\");\n    }\n    return Err(e.into());\n}","preventionTips":["Always enable a TLS backend together with local-http","Verify with `cargo tree -f '{p} {f}'` that a TLS feature is active","Use rustls for portable pure-Rust builds"],"tags":["feature-flags","tls","proxy"],"backgroundTag":"feature-not-enabled","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}