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

  1. Check the status message in the error (it is the proxy's status text) to identify why the tunnel was refused
  2. 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
  3. Verify with curl -x $HTTPS_PROXY https://target-host that the proxy can reach the target; fix proxy ACLs/whitelisting if blocked
  4. 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
  5. 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

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


AI-assisted analysis of gorilla/websocket@e064f32e36 (2026-08-31). Data as JSON: /api/errors/a6a8c0211169ee66. Report an issue: GitHub.