cloudflare/cloudflared · error

Hostname(actually a URL) %s has invalid escape characters %s

Error message

Hostname(actually a URL) %s has invalid escape characters %s

What it means

When ValidateHostname receives a value containing ':' or '%3A' it treats it as a URL rather than a bare hostname and attempts url.PathUnescape. This error fires when the percent-encoding is malformed (invalid escape sequences), so the input cannot be unescaped into a parseable URL.

Source

Thrown at validation/validation.go:37

	accessDomain    = "cloudflareaccess.com"
	accessCertPath  = "/cdn-cgi/access/certs"
	accessJwtHeader = "Cf-access-jwt-assertion"
)

var (
	supportedProtocols = []string{"http", "https", "rdp", "ssh", "smb", "tcp"}
	validationTimeout  = time.Duration(30 * time.Second)
)

func ValidateHostname(hostname string) (string, error) {
	if hostname == "" {
		return "", nil
	}
	// users gives url(contains schema) not just hostname
	if strings.Contains(hostname, ":") || strings.Contains(hostname, "%3A") {
		unescapeHostname, err := url.PathUnescape(hostname)
		if err != nil {
			return "", fmt.Errorf("Hostname(actually a URL) %s has invalid escape characters %s", hostname, unescapeHostname)
		}
		hostnameToURL, err := url.Parse(unescapeHostname)
		if err != nil {
			return "", fmt.Errorf("Hostname(actually a URL) %s has invalid format %s", hostname, hostnameToURL)
		}
		asciiHostname, err := idna.ToASCII(hostnameToURL.Hostname())
		if err != nil {
			return "", fmt.Errorf("Hostname(actually a URL) %s has invalid ASCII encdoing %s", hostname, asciiHostname)
		}
		return asciiHostname, nil
	}

	asciiHostname, err := idna.ToASCII(hostname)
	if err != nil {
		return "", fmt.Errorf("Hostname %s has invalid ASCII encdoing %s", hostname, asciiHostname)
	}
	hostnameToURL, err := url.Parse(asciiHostname)
	if err != nil {

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Pass a plain hostname (e.g. example.com) without ports, schemes, or percent-encoding
  2. If a URL is needed, pass a well-formed one: https://example.com:8080 — ensure % sequences are valid percent-escapes
  3. Decode the value yourself correctly before passing it in
  4. Check for stray '%' characters introduced by copy-paste and remove or fix them

Example fix

// before
hostname, err := validation.ValidateHostname("example.com%3A")
// after
hostname, err := validation.ValidateHostname("example.com")
Defensive patterns

Strategy: validation

Validate before calling

func validHostOrURL(s string) bool {
    if s == "" { return false }
    if strings.Contains(s, ":") || strings.Contains(s, "%3A") {
        unesc, err := url.PathUnescape(s)
        if err != nil { return false }
        _, err = url.Parse(unesc)
        return err == nil
    }
    return true
}

Try / catch

host, err := validation.ValidateHostname(input)
if err != nil {
    if strings.Contains(err.Error(), "invalid escape characters") {
        return fmt.Errorf("hostname %q contains malformed percent-encoding; pass a plain hostname", input)
    }
    return err
}

Prevention

When it happens

Trigger: Calling ValidateHostname with a string containing ':' or '%3A' that url.PathUnescape fails on, e.g. "example.com%3" (truncated percent-escape) or stray '%' characters in a tunnel hostname/URL argument.

Common situations: Users passing a full URL (with port/scheme) where cloudflared expects only a hostname, with hand-mangled percent-encoding; copy-pasted URLs from logs or HTML where '%' got corrupted.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/e6d26dd0c92a8821. Report an issue: GitHub.