gorilla/websocket · error
f[1] (proxy response status text)
Error message
f[1] (proxy response status text)
What it means
This error is returned by DialContext when an HTTP proxy responds to the CONNECT request with a status code other than 200. The library closes the connection and surfaces the proxy's own status message (e.g. '407 Proxy Authentication Required' → 'Proxy Authentication Required') as the error text. It means the proxy refused to open the tunnel to the target host, not that the WebSocket handshake itself failed.
Source
Thrown at proxy.go:101
if err != nil {
conn.Close()
return nil, err
}
// Close the response body to silence false positives from linters. Reset
// the buffered reader first to ensure that Close() does not read from
// conn.
// Note: Applications must call resp.Body.Close() on a response returned
// http.ReadResponse to inspect trailers or read another response from the
// buffered reader. The call to resp.Body.Close() does not release
// resources.
br.Reset(bytes.NewReader(nil))
_ = resp.Body.Close()
if resp.StatusCode != http.StatusOK {
_ = conn.Close()
f := strings.SplitN(resp.Status, " ", 2)
return nil, errors.New(f[1])
}
return conn, nil
}
View on GitHub (pinned to e064f32e36)
Solutions
- Check the status message in the error (it is the proxy's status text) to identify why the tunnel was refused
- If it is a 407, embed credentials in the proxy URL, e.g. http://user:pass@proxy:8080, or configure them via HTTPS_PROXY, since gorilla only supports Basic proxy auth
- Verify with curl -x $HTTPS_PROXY https://target-host that the proxy can reach the target; fix proxy ACLs/whitelisting if blocked
- Confirm env vars (HTTPS_PROXY/HTTP_PROXY/NO_PROXY) point at the correct reachable proxy, or unset Proxy in the Dialer if no proxy is needed
- Retry later or use a different proxy if the status is 502/503 (upstream outage)
Example fix
// before (407: proxy needs auth)
u := websocket.Upgrader{}
_, _, err := websocket.DefaultDialer.DialContext(ctx, "wss://example.com/ws", nil)
// err: "Proxy Authentication Required"
// after: supply Basic proxy credentials in the proxy URL
proxyURL, _ := url.Parse("http://user:pass@proxy.corp:8080")
dialer := &websocket.Dialer{
Proxy: http.ProxyURL(proxyURL),
HandshakeTimeout: 10 * time.Second,
}
conn, _, err := dialer.DialContext(ctx, "wss://example.com/ws", nil) Defensive patterns
Strategy: retry
Validate before calling
proxyURL, err := http.ProxyFromEnvironment(&http.Request{URL: targetURL})
if err != nil {
return nil, fmt.Errorf("bad proxy config: %w", err)
}
if proxyURL != nil && proxyURL.User == nil && os.Getenv("HTTPS_PROXY") != "" {
log.Printf("warning: proxy %s has no credentials; CONNECT may return 407", proxyURL.Host)
} Type guard
func isProxyStatusError(err error) bool {
if err == nil {
return false
}
for _, code := range []int{403, 407, 502, 503} {
if strings.Contains(err.Error(), http.StatusText(code)) {
return true
}
}
return false
} Try / catch
conn, _, err := dialer.DialContext(ctx, wsURL, nil)
if err != nil {
if isProxyStatusError(err) {
if strings.Contains(err.Error(), http.StatusText(407)) {
// fix proxy credentials, then retry once
dialer.Proxy = http.ProxyURL(proxyWithAuth)
conn, _, err = dialer.DialContext(ctx, wsURL, nil)
}
// 502/503: retry with backoff
if backoff := retryWithBackoff(ctx); backoff != nil {
conn, _, err = dialer.DialContext(ctx, wsURL, nil)
}
}
if err != nil {
return fmt.Errorf("ws dial failed: %w", err)
}
} Prevention
- Put credentials in the proxy URL (user:pass@host) before deploying behind a corporate proxy
- Prefer http.ProxyFromEnvironment and keep HTTPS_PROXY/NO_PROXY correct per environment
- Smoke-test the CONNECT path with curl -x $HTTPS_PROXY https://target in CI
- Support only proxies that allow Basic auth, since gorilla has no NTLM/Kerberos support
- Add a short HandshakeTimeout so proxy failures fail fast instead of hanging
When it happens
Trigger: dialer.Dial/DialContext called with Proxy set (http.ProxyFromEnvironment or custom) where the proxy answers the CONNECT with e.g. 407 (missing proxy credentials), 403 (target blocked by policy), 502/503 (proxy cannot reach target or is overloaded).
Common situations: Corporate environments where HTTPS_PROXY is set but credentials are missing from the proxy URL (user:pass@host) or the proxy requires NTLM/Kerberos auth gorilla does not support; VPN/network changes making the proxy unreachable to the target; proxy ACLs blocking the destination port 443/80.
Related errors
- websocket: bad handshake
- websocket: invalid compression negotiation
- malformed ws or wss URL
- websocket: duplicate header not allowed:
- websocket: protocol %q was given but is not supported;sharin
AI-assisted analysis of gorilla/websocket@e064f32e36 (2026-08-31).
Data as JSON: /api/errors/a6a8c0211169ee66.
Report an issue: GitHub.