caddyserver/caddy · error

parsing upstream URL: %v

Error message

parsing upstream URL: %v

What it means

A scheme-bearing upstream address failed url.Parse, and the failure was not the port-range special case (or the address had no ':' at all before the suspected port range). The '%v' suffix carries Go's url.Parse error, usually 'invalid port' or a malformed URL.

Source

Thrown at modules/caddyhttp/reverseproxy/addresses.go:84

	var network, scheme, host, port string

	if strings.Contains(upstreamAddr, "://") {
		// we get a parsing error if a placeholder is specified
		// so we return a more user-friendly error message instead
		// to explain what to do instead
		if strings.Contains(upstreamAddr, "{") {
			return parsedAddr{}, fmt.Errorf("due to parsing difficulties, placeholders are not allowed when an upstream address contains a scheme")
		}

		toURL, err := url.Parse(upstreamAddr)
		if err != nil {
			// if the error seems to be due to a port range,
			// try to replace the port range with a dummy
			// single port so that url.Parse() will succeed
			if strings.Contains(err.Error(), "invalid port") && strings.Contains(err.Error(), "-") {
				index := strings.LastIndex(upstreamAddr, ":")
				if index == -1 {
					return parsedAddr{}, fmt.Errorf("parsing upstream URL: %v", err)
				}
				portRange := upstreamAddr[index+1:]
				if strings.Count(portRange, "-") != 1 {
					return parsedAddr{}, fmt.Errorf("parsing upstream URL: parse \"%v\": port range invalid: %v", upstreamAddr, portRange)
				}
				toURL, err = url.Parse(strings.ReplaceAll(upstreamAddr, portRange, "0"))
				if err != nil {
					return parsedAddr{}, fmt.Errorf("parsing upstream URL: %v", err)
				}
				port = portRange
			} else {
				return parsedAddr{}, fmt.Errorf("parsing upstream URL: %v", err)
			}
		}
		if port == "" {
			port = toURL.Port()
		}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Check the wrapped url.Parse error text and fix the host/port portion of the upstream address.
  2. Ensure the port is numeric and in 1-65535, and that port ranges contain exactly one dash (e.g. :8080-8090).
  3. URL-encode or bracket IPv6 literals, e.g. 'http://[::1]:8080'.

Example fix

# before
reverse_proxy http://backend:notaport

# after
reverse_proxy http://backend:8080
Defensive patterns

Strategy: validation

Validate before calling

// pre-check any scheme-bearing upstream with the same parser Go uses
if _, err := url.Parse(addr); err != nil {
    return fmt.Errorf("upstream %q is not a parseable URL: %v", addr, err)
}

Prevention

When it happens

Trigger: Calling parseUpstreamDialAddress with values like 'https://host:notaport', 'http://[bad', or an address whose error message contains 'invalid port' but has no last colon; also reached from 'caddy reverse-proxy --to' with such a value.

Common situations: Non-numeric or out-of-range ports, unescaped characters in the host, or a port range error where LastIndex(':') finds no colon.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/4daa0da3ba7fbf7f. Report an issue: GitHub.