XTLS/Xray-core · error

invalid URL:

Error message

invalid URL: 

What it means

Thrown by FetchHTTPContent after utils.SplitHTTPUnixURL splits the target into an HTTP URL and an optional socket path. The remaining HTTP part is passed to url.Parse, which rejects strings containing control characters or otherwise malformed URL syntax. This is the entry point for Xray's remote config fetching, supporting plain http(s) plus Unix/abstract-socket targets.

Source

Thrown at main/confloader/external/external.go:59

	return
}

// FetchHTTPContent issues an HTTP GET against either a regular HTTP(S) URL
// or a Unix socket HTTP endpoint.
//
//	http(s)://host/api          regular HTTP(S)
//	/path/to/socket.sock[:/api] filesystem socket
//	@abstract[:/api]            abstract socket (Linux/Android)
//	@@padded[:/api]             padded abstract socket (HAProxy compat)
//
// When the ":/" separator is omitted on a socket target, the request is
// made to "/".
func FetchHTTPContent(target string) ([]byte, error) {
	httpURL, socketPath := utils.SplitHTTPUnixURL(target)

	parsedTarget, err := url.Parse(httpURL)
	if err != nil {
		return nil, errors.New("invalid URL: ", target).Base(err)
	}

	client := &http.Client{
		Timeout: 30 * time.Second,
	}

	if socketPath != "" {
		dialAddr := utils.ResolveSocketPath(socketPath)
		client.Transport = &http.Transport{
			DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
				var d net.Dialer
				return d.DialContext(ctx, "unix", dialAddr)
			},
		}
	}

	resp, err := client.Do(&http.Request{
		Method: "GET",

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Inspect the exact target string passed on the command line or in code; strip leading/trailing whitespace, newlines and carriage returns
  2. Ensure the URL has a valid scheme: http:// or https:// for network, or /path, @name, @@name forms for sockets
  3. URL-encode any spaces or special characters in the path/query portion of the target
  4. If the target is a local file, remove any http-like prefix and pass the filesystem path instead

Example fix

// before
content, err := external.FetchHTTPContent("http://example.com/conf x.json\n")

// after
target := strings.TrimSpace("http://example.com/conf%20x.json")
content, err := external.FetchHTTPContent(target)
Defensive patterns

Strategy: validation

Validate before calling

import ("net/url"; "strings")

func validFetchTarget(target string) bool {
    t := strings.TrimSpace(target)
    if t == "" { return false }
    httpPart, _ := utils.SplitHTTPUnixURL(t) // or replicate the split
    _, err := url.Parse(httpPart)
    return err == nil
}

Try / catch

if content, err := external.FetchHTTPContent(t); err != nil {
    if strings.HasPrefix(err.Error(), "invalid URL") { fixTarget(t); continue }
    return err
}

Prevention

When it happens

Trigger: Calling confloader.LoadConfig with a target like "http(s)://host/api", "/path/to/socket.sock:/api", "@abstract:/api" or "@@padded:/api" where the URL portion contains control characters (e.g. raw newline/tab), an unsupported scheme remnant, or other input url.Parse refuses.

Common situations: Typos in the -config flag (missing scheme, stray whitespace or CR from copy-pasting a URL, unescaped spaces), or a Windows-style path accidentally passed as an http URL; also malformed socket-target syntax that SplitHTTPUnixURL does not normalize.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/11b5c0c027c8d70a. Report an issue: GitHub.