DioxusLabs/dioxus · error · anyhow::Error
HTTP handshake failed: {e}
Error message
HTTP handshake failed: {e} What it means
After a successful TCP connect, send_with_retry performs a plaintext HTTP/1.1 handshake on that socket via hyper's http1::handshake. If the peer does not speak HTTP/1.1 in the clear — a TLS server receiving plaintext bytes, an HTTP/2 prior-knowledge endpoint, or a non-HTTP service — the handshake error surfaces through handle_error as this message.
Source
Thrown at packages/cli/src/serve/proxy.rs:59
if start.elapsed() >= max_wait {
return Err(handle_error(anyhow::anyhow!(
"Backend not ready after {max_wait:?}: {e}"
)));
}
tracing::debug!("Backend not ready, retrying in {backoff:?}...");
tokio::time::sleep(backoff).await;
backoff = (backoff * 2).min(std::time::Duration::from_secs(2));
}
}
};
// Wrap the TCP stream for hyper
let io = TokioIo::new(stream);
// Perform HTTP/1.1 handshake on the same connection
let (mut sender, conn) = http1::handshake(io)
.await
.map_err(|e| handle_error(anyhow::anyhow!("HTTP handshake failed: {e}")))?;
// Spawn connection driver to keep it alive
tokio::spawn(async move {
if let Err(e) = conn.await {
tracing::debug!("Connection closed: {e}");
}
});
// Send request through the established connection (streaming body)
sender
.send_request(req)
.await
.map_err(|e| handle_error(anyhow::anyhow!("Request failed: {e}")))
}
/// Add routes to the router handling the specified proxy config.
///
/// We will proxy requests directed at either:View on GitHub (pinned to 393d190a80)
Solutions
- Point the proxy at the backend's plain-HTTP listener; this code path only speaks HTTP/1.1 without TLS
- If the backend is HTTPS-only, terminate TLS locally (caddy/nginx/stunnel) and proxy to that local plain port
- Verify with curl http://host:port/ that the backend actually answers plaintext HTTP/1.1
- Check for port mix-ups between TLS (443/8443) and plain (80/8080) listeners
Example fix
// Dioxus.toml — before: TLS port addressed as plain HTTP [web.proxy] backend = "http://api.internal:443/api" // after: terminate TLS locally and proxy plain HTTP [web.proxy] backend = "http://127.0.0.1:8080/api"
Defensive patterns
Strategy: validation
Validate before calling
# Confirm the backend speaks plaintext HTTP/1.1 before configuring the proxy curl --http1.1 -fsS http://127.0.0.1:8080/api >/dev/null && echo ok || echo 'not a plain HTTP/1.1 endpoint'
Prevention
- The dx proxy speaks plaintext HTTP/1.1 only — terminate TLS at or before the backend
- Double-check scheme and port when copying backend URLs
- Test with curl first whenever the handshake error appears
When it happens
Trigger: Configuring [web.proxy].backend with http:// against an HTTPS-only port (the TLS server rejects the plaintext handshake); proxying to a gRPC/HTTP-2 service; pointing the backend URL at a database or other raw TCP service.
Common situations: Using an https://-style URL but with the scheme dropped to http; reverse-proxy setups where TLS termination is expected on the dx side but none exists; port confusion between the TLS and plain listeners of the same backend.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Backend not ready after {max_wait:?}: {e}
- Request failed: {e}
- Failed to create new router after hot-patch!
- Syntax Error in line {line} column {column}: {err}
- Package type '{invalid:?}' is not supported for bundle forma
AI-assisted analysis of DioxusLabs/dioxus@393d190a80 (2026-08-16).
Data as JSON: /api/errors/b9f68cc122c6128b.
Report an issue: GitHub.