MHSanaei/3x-ui · error

create socks5 dialer: %w

Error message

create socks5 dialer: %w

What it means

When the proxy scheme is socks5/socks5h, NewHTTPClient builds a dialer with golang.org/x/net/proxy.SOCKS5; if that constructor fails the error is wrapped as 'create socks5 dialer: %w'. proxy.SOCKS5 itself almost never fails for a well-formed address — it fails when the 'tcp' network is unknown to the registered forward dialer or the proxy address is not host:port, so in practice this surfaces malformed host:port strings that still passed url.Parse.

Source

Thrown at internal/util/netproxy/netproxy.go:49

	}

	parsed, err := url.Parse(proxyURL)
	if err != nil {
		return nil, fmt.Errorf("parse proxy url: %w", err)
	}

	transport := baseTransport()

	switch strings.ToLower(parsed.Scheme) {
	case "socks5", "socks5h":
		var auth *proxy.Auth
		if parsed.User != nil {
			password, _ := parsed.User.Password()
			auth = &proxy.Auth{User: parsed.User.Username(), Password: password}
		}
		dialer, err := proxy.SOCKS5("tcp", parsed.Host, auth, proxy.Direct)
		if err != nil {
			return nil, fmt.Errorf("create socks5 dialer: %w", err)
		}
		if contextDialer, ok := dialer.(proxy.ContextDialer); ok {
			transport.DialContext = contextDialer.DialContext
		} else {
			transport.DialContext = func(_ context.Context, network, addr string) (net.Conn, error) {
				return dialer.Dial(network, addr)
			}
		}
	case "http", "https":
		transport.Proxy = http.ProxyURL(parsed)
	default:
		return nil, fmt.Errorf("unsupported proxy scheme %q", parsed.Scheme)
	}

	return &http.Client{Timeout: timeout, Transport: transport}, nil
}

func baseTransport() *http.Transport {

View on GitHub (pinned to ad32144c42)

Solutions

  1. Include an explicit port: socks5://127.0.0.1:1080.
  2. Bracket IPv6: socks5://[::1]:1080.
  3. Verify the address part is exactly host:port (u.Host) before calling NewHTTPClient.
  4. Check the wrapped error message with %w unwrapping to confirm which address string reached proxy.SOCKS5.

Example fix

// before
proxyURL := "socks5://127.0.0.1" // no port -> dialer creation fails

// after
proxyURL := "socks5://127.0.0.1:1080"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(proxyURL)
if err != nil { return err }
if strings.EqualFold(u.Scheme, "socks5") || strings.EqualFold(u.Scheme, "socks5h") {
    if u.Port() == "" {
        return fmt.Errorf("socks5 proxy %q must include :port", proxyURL)
    }
}

Try / catch

client, err := netproxy.NewHTTPClient(proxyURL, timeout)
if err != nil && strings.Contains(err.Error(), "socks5 dialer") {
    return fmt.Errorf("check socks5 proxy host:port in %q: %w", proxyURL, err)
}

Prevention

When it happens

Trigger: NewHTTPClient with scheme socks5/socks5h where parsed.Host lacks a port ('socks5://1.2.3.4' — Host='1.2.3.4', no :port) or is otherwise not resolvable as an address by proxy.SOCKS5's internal net.Dial registration.

Common situations: Proxy setting entered without a port; IPv6 address unbracketed so the colons confuse host:port splitting; hostname with underscores that url parsing tolerates.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/499a8c360d5518db. Report an issue: GitHub.