shadowsocks/shadowsocks-rust · error
unexpected response from http://detectportal.firefox.com/suc
Error message
unexpected response from http://detectportal.firefox.com/success.txt, {:?} What it means
check_request_tcp_firefox probes a candidate proxy by requesting http://detectportal.firefox.com/success.txt and accepts 200 or 204. When the response cannot be parsed by httparse or the status code is neither 200 nor 204, the library concludes the proxy path is unusable and throws InvalidData including the raw bytes received.
Source
Thrown at crates/shadowsocks-service/src/local/loadbalancing/ping_balancer.rs:914
&addr,
self.server.connect_opts_ref(),
)
.await?;
stream.write_all(GET_BODY).await?;
let mut reader = BufReader::new(stream);
let mut buf = Vec::new();
reader.read_until(b'\n', &mut buf).await?;
let mut headers = [httparse::EMPTY_HEADER; 1];
let mut response = httparse::Response::new(&mut headers);
if response.parse(&buf).is_ok() && matches!(response.code, Some(200) | Some(204)) {
return Ok(());
}
Err(Error::new(
ErrorKind::InvalidData,
format!(
"unexpected response from http://detectportal.firefox.com/success.txt, {:?}",
ByteStr::new(&buf)
),
))
}
async fn check_request_udp(&self) -> io::Result<()> {
// TransactionID: 0x1234
// Flags: 0x0100 RD
// Questions: 0x0001
// Answer RRs: 0x0000
// Authority RRs: 0x0000
// Additional RRs: 0x0000
// Queries
// - QNAME: \x07 firefox \x03 com \x00
// - QTYPE: 0x0001 AView on GitHub (pinned to 8eb0f0a65b)
Solutions
- Test the failing proxy node manually; replace or remove it from the server list if it cannot relay traffic.
- Check for captive-portal or ISP interception rewriting the probe response.
- Ensure the remote server can reach detectportal.firefox.com (DNS + egress).
- Use the chromium 204 probe or a custom check URL if this host is unreliable in your environment.
Defensive patterns
Strategy: retry
Validate before calling
// precheck reachability of the probe host through an alternate path // if detectportal.firefox.com is blocked locally, probe results are unreliable
Try / catch
if let Err(e) = check_request(&server).await {
if e.kind() == std::io::ErrorKind::InvalidData {
// mark server unhealthy instead of aborting the balancer
server.set_score(...); schedule_recheck(&server);
}
} Prevention
- Run both firefox and chromium probes so one blocked host doesn't disqualify good nodes
- Watch for captive-portal networks (hotel/airport Wi-Fi) where probes always fail
- Keep the balancer in LivenessCheckMode so failing nodes re-check instead of being dropped permanently
When it happens
Trigger: Calling check_request (which dispatches to check_request_tcp_firefox) when the proxy returns non-HTTP data, an error/redirect page, or truncated output for the success.txt probe.
Common situations: Captive portals returning their login page instead of success.txt, blocked detectportal.firefox.com on the server side, dead proxy nodes, or misconfigured DNS on the remote server.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- unexpected response from http://clients3.google.com/generate
- unexpected response from 8.8.8.8:53
- TCP mode have to be enabled for http
- invalid outbound_proxy
- invalid outbound_bind_addr
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/d71e66acc864c201.
Report an issue: GitHub.