nats-io/nats-server · error
unexpected proxy URL parse error (URL was pre-validated): %v
Error message
unexpected proxy URL parse error (URL was pre-validated): %v
What it means
establishHTTPProxyTunnel failed to re-parse the proxy URL string that was already validated during configuration. This is a defensive/unexpected path — by the time the tunnel is established the URL passed validation, so url.Parse should never fail. Hitting it indicates an internal inconsistency (URL mutated between validation and dial) rather than a user config problem.
Source
Thrown at server/leafnode.go:626
}
s.leafNodeOpts.resolver = opts.LeafNode.resolver
if s.leafNodeOpts.resolver == nil {
s.leafNodeOpts.resolver = net.DefaultResolver
}
s.leafNodeOpts.dialer = opts.LeafNode.dialer
if s.leafNodeOpts.dialer == nil {
s.leafNodeOpts.dialer = natsDialTimeout
}
}
const sharedSysAccDelay = 250 * time.Millisecond
// establishHTTPProxyTunnel establishes an HTTP CONNECT tunnel through a proxy server
func establishHTTPProxyTunnel(proxyURL, targetHost string, timeout time.Duration, username, password string) (net.Conn, error) {
proxyAddr, err := url.Parse(proxyURL)
if err != nil {
// This should not happen since proxy URL is validated during configuration parsing
return nil, fmt.Errorf("unexpected proxy URL parse error (URL was pre-validated): %v", err)
}
// Connect to the proxy server
conn, err := natsDialTimeout("tcp", proxyAddr.Host, timeout)
if err != nil {
return nil, fmt.Errorf("failed to connect to proxy: %v", err)
}
// Set deadline for the entire proxy handshake
if err := conn.SetDeadline(time.Now().Add(timeout)); err != nil {
conn.Close()
return nil, fmt.Errorf("failed to set deadline: %v", err)
}
req := &http.Request{
Method: http.MethodConnect,
URL: &url.URL{Opaque: targetHost}, // Opaque is required for CONNECT
Host: targetHost,View on GitHub (pinned to 3a66a489d2)
Solutions
- Check whether any code mutates the remote's Proxy URL after validation
- Call establishHTTPProxyTunnel only with URLs that passed validateLeafNodeProxyOptions
- If reproducible with stock config, report as a bug with the exact proxy URL value
Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := url.Parse(proxyURL); err != nil {
return fmt.Errorf("proxy URL invalid before tunnel: %w", err)
} Type guard
func parseableProxyURL(raw string) bool {
_, err := url.Parse(raw)
return err == nil
} Try / catch
conn, err := establishHTTPProxyTunnel(purl, host, timeout, user, pass)
if err != nil {
if strings.Contains(err.Error(), "unexpected proxy URL parse error") {
log.Fatalf("BUG: proxy URL mutated after validation: %v", err)
}
return err
} Prevention
- Treat this as an internal bug and file it if seen with stock config
- Never mutate RemoteLeafOpts Proxy URL after config parsing
- Only call establishHTTPProxyTunnel with pre-validated URLs
When it happens
Trigger: url.Parse(proxyURL) returning an error inside establishHTTPProxyTunnel despite pre-validation in validateLeafNodeProxyOptions — practically only if the stored proxy URL string is corrupt or modified after parsing.
Common situations: Bugs in code that rewrites the proxy URL between config validation and connection; custom test harnesses calling establishHTTPProxyTunnel with an unvalidated string.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- proxy URL must specify a host
- not same origin
- error setting up update handling: %v
- proxy trusted key %q is invalid
- invalid proxy URL: %v
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/006a43af6e6d3967.
Report an issue: GitHub.