fish2018/pansou · error

创建SOCKS5代理失败

Error message

创建SOCKS5代理失败: %w

What it means

If the configured proxy URL has scheme socks5, the plugin calls golang.org/x/net/proxy.FromURL to build a SOCKS5 dialer. FromURL returns an error when it cannot construct the dialer — most commonly an unknown scheme (the socks5 dialer must be registered, e.g. via an import of x/net/proxy/socks5) or invalid embedded credentials — and the plugin wraps it as '创建SOCKS5代理失败: %w'.

Solutions

  1. Ensure the socks5 dialer is registered: import _ "golang.org/x/net/proxy/socks5" so proxy.FromURL recognizes the socks5 scheme.
  2. Check the wrapped %w error; if it says unknown scheme, fix the scheme spelling (socks5, not sock5/socks) or register a custom dialer.
  3. URL-encode username/password in the proxy URL (url.QueryEscape) if credentials contain special characters.
  4. If the proxy is actually HTTP, use scheme http:// instead of socks5:// so the non-socks branch builds the transport.

Example fix

// before (dialer unknown)
import "golang.org/x/net/proxy"
// after
import (
    "golang.org/x/net/proxy"
    _ "golang.org/x/net/proxy/socks5" // registers socks5/socks5h schemes
)
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the socks5 dialer is available before configuring the proxy
if strings.HasPrefix(strings.ToLower(cfg.ProxyURL), "socks5") {
    u, _ := url.Parse(cfg.ProxyURL)
    if _, err := proxy.FromURL(u, proxy.Direct); err != nil {
        return fmt.Errorf("socks5 dialer unavailable: %w", err)
    }
}

Try / catch

transport, err := buildProxyTransport(cfg)
if err != nil && strings.Contains(err.Error(), "创建SOCKS5代理失败") {
    log.Warn("SOCKS5 proxy unavailable, using direct connection")
    transport, err = buildPlainTransport(cfg)
}

Prevention

When it happens

Trigger: ProxyURL scheme is socks5 (or socks5h) and proxy.FromURL fails: typically because the x/net/proxy/socks5 package isn't linked (FromURL returns 'proxy: unknown scheme' for socks5 without a registered dialer), or the userinfo (username/password) in the URL is invalid/undecodable.

Common situations: Project missing the blank import _ "golang.org/x/net/proxy/socks5"; proxy requires auth and credentials contain characters needing escaping; user set socks5:// but the proxy is actually HTTP; typo like sock5:// handled elsewhere.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/d4bbcc5bcc3baab3. Report an issue: GitHub.

Appendix: source

Thrown at plugin/gying/gying.go:1640

	if !baseTransportField.IsValid() || baseTransportField.IsNil() {
		return fmt.Errorf("未找到底层 transport")
	}

	baseTransportValue := reflect.NewAt(baseTransportField.Type(), unsafe.Pointer(baseTransportField.UnsafeAddr())).Elem()
	baseTransport, ok := baseTransportValue.Interface().(*http.Transport)
	if !ok || baseTransport == nil {
		return fmt.Errorf("底层 transport 无效")
	}

	proxyURL, err := url.Parse(config.AppConfig.ProxyURL)
	if err != nil {
		return fmt.Errorf("解析代理地址失败: %w", err)
	}

	if proxyURL.Scheme == "socks5" {
		dialer, err := proxy.FromURL(proxyURL, proxy.Direct)
		if err != nil {
			return fmt.Errorf("创建SOCKS5代理失败: %w", err)
		}
		baseTransport.Proxy = nil
		baseTransport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
			return dialer.Dial(network, addr)
		}
	} else {
		baseTransport.Proxy = http.ProxyURL(proxyURL)
	}

	if DebugLog {
		fmt.Printf("[Gying] 已应用代理到scraper: %s\n", config.AppConfig.ProxyURL)
	}

	return nil
}

func (p *GyingPlugin) solveBotChallenge(scraper *cloudscraper.Scraper, requestURL string, body []byte) error {
	matches := challengeJSONPattern.FindSubmatch(body)

View on GitHub (pinned to beaa561337)