shadowsocks/shadowsocks-rust · error
unexpected response from http://clients3.google.com/generate
Error message
unexpected response from http://clients3.google.com/generate_204, {:?} What it means
In shadowsocks-service's ping_balancer, check_request_tcp_chromium sends an HTTP request to http://clients3.google.com/generate_204 through a candidate proxy server and expects a 204 response proving the server works. If httparse cannot parse the reply or the status code is not 204, the server (or the path through it) is broken, so InvalidData is thrown with the raw response bytes in the message for diagnosis.
Source
Thrown at crates/shadowsocks-service/src/local/loadbalancing/ping_balancer.rs:875
&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(204)) {
return Ok(());
}
Err(Error::new(
ErrorKind::InvalidData,
format!(
"unexpected response from http://clients3.google.com/generate_204, {:?}",
ByteStr::new(&buf)
),
))
}
/// Detect TCP connectivity with Firefox's http://detectportal.firefox.com/success.txt
async fn check_request_tcp_firefox(&self) -> io::Result<()> {
use std::io::{Error, ErrorKind};
const GET_BODY: &[u8] =
b"GET /success.txt HTTP/1.1\r\nHost: detectportal.firefox.com\r\nConnection: close\r\nAccept: */*\r\n\r\n";
let addr = Address::DomainNameAddress("detectportal.firefox.com".to_owned(), 80);
let mut stream = ProxyClientStream::connect_with_opts(View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Check whether the proxy server actually relays traffic (test with curl through the same proxy).
- Switch to another server in the balancer or update the server list; this node is failing the liveness probe.
- Verify no local firewall/ISP interception is rewriting HTTP responses (test generate_204 directly).
- If the target is blocked in your network, point the probe at a reachable URL by adjusting the balancer's check logic.
Example fix
// before: server fails the probe silently or is removed
let balancer = PingBalancerBuilder::new(check_adapter, mode).build().await;
// after: handle probe failures gracefully by scheduling re-check instead of treating as fatal
match check_request(server).await {
Ok(()) => balancer.add_server(server, estimate),
Err(err) => tracing::warn!(?err, "server failed connectivity check, rescheduling"),
} Defensive patterns
Strategy: retry
Validate before calling
// precheck: only feed servers into the balancer that can reach the probe tcping(server_addr, Duration::from_secs(3)).await.is_ok()
Try / catch
match check_request(server).await {
Ok(()) => balancer.add_server(server, estimate),
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
tracing::warn!("probe failed (unexpected response), rescheduling check: {e}");
schedule_recheck(server);
}
Err(e) => return Err(e),
} Prevention
- Pre-tcping server latency before adding to the balancer
- Exclude nodes known to be behind captive portals
- Log the raw probe response from the error message to diagnose hijacks
- Use multiple probe targets (chromium + firefox) for robustness
When it happens
Trigger: Running check_request_tcp_chromium (via loadbalancer's check_request) when the proxy server returns garbage, an HTTP error page, a captive-portal redirect (302/200), or closes/truncates the connection instead of returning HTTP 204 from the generate_204 endpoint.
Common situations: Dead or censored proxy nodes, captive portals intercepting traffic, GFW-style hijacking returning reset/redirect pages, or a node that resolves generate_204 incorrectly. Commonly surfaced during network-change events or periodic server health checks.
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://detectportal.firefox.com/suc
- 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/cc8345b57364058a.
Report an issue: GitHub.