You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Connect errors lose their cause, so cert failures are retried and messages say only "client error (Connect)" #116
hyper-util's Display for its client error is just client error ({kind:?}). The real cause (certificate verify failed, connection refused, proxy rejected CONNECT, and so on) is in source(), which is never read. Two things follow:
The message doesn't say why. Every connect failure reads request failed: client error (Connect), whether the cert was bad, the port was closed, or a proxy refused the tunnel.
TLS and certificate failures are retried. The check for "ssl", "tls" or "certificate" never matches, so they're classified as ErrorKind::Connection, which is_retryable retries. With the default retries=1, every host with a bad cert costs an extra attempt plus at least retry_wait_min_ms of backoff.
This happens on direct requests too, not just through a proxy.
Reproduction
verify_certs=True against the self-signed server in tests/tls_integration.rs (test_verify_certs_true_rejects_self_signed) fails with:
The test only asserts is_err(), so it passes anyway.
Proposed Solution
Walk the error's source() chain, append the causes to the message, and run the TLS check against the full chain, so a cert failure is ErrorKind::Tls and isn't retried. Tighten test_verify_certs_true_rejects_self_signed to assert ErrorKind::Tls.
The error text gets longer as a result, so anything matching on the exact string client error (Connect) would need to change.
This is fixed on the 1.0 branch (#128), which hasn't merged yet.
TLS failures: the connector now records why a handshake failed, and the client looks that up instead of relying on hyper-util's top-level error. The error comes back as a TLS error with the actual reason, for example "certificate verification failed: ..." or "no cipher suite in common". TLS errors aren't retried, so a bad cert no longer costs an extra attempt.
Failures before TLS (020335b): a refused connection, a DNS failure or a proxy refusing the tunnel now carries the cause from further down the error chain, for example tcp connect error: Connection refused (os error 111). A connect timeout is now reported as a timeout instead of a retryable connection error, which matches what the direct path already did. The same commit also removes the old substring check from dispatch_direct, which could never match.
Activity
liquidsec commentedon Oct 26, 2026
This is fixed on the 1.0 branch (#128), which hasn't merged yet.
tcp connect error: Connection refused (os error 111). A connect timeout is now reported as a timeout instead of a retryable connection error, which matches what the direct path already did. The same commit also removes the old substring check fromdispatch_direct, which could never match.I'll leave this open until #128 merges.