cloudflare/cloudflared · error

%s is not a valid hostname

Error message

%s is not a valid hostname

What it means

dnsRouteFromArg validates the user-supplied hostname argument for `cloudflared tunnel route dns` with validateHostname(userHostname, true). If validation fails, it rejects the argument with '<hostname> is not a valid hostname'. The hostname must be a syntactically valid DNS name (FQDN allowed, wildcards only as the leading label).

Source

Thrown at cmd/cloudflared/tunnel/subcommands.go:957

			},
			buildRouteIPSubcommand(),
		},
	}
}

func dnsRouteFromArg(c *cli.Context, overwriteExisting bool) (cfapi.HostnameRoute, error) {
	const (
		userHostnameIndex = 1
		expectedNArgs     = 2
	)
	if c.NArg() != expectedNArgs {
		return nil, cliutil.UsageError("Expected %d arguments, got %d", expectedNArgs, c.NArg())
	}
	userHostname := c.Args().Get(userHostnameIndex)
	if userHostname == "" {
		return nil, cliutil.UsageError("The third argument should be the hostname")
	} else if !validateHostname(userHostname, true) {
		return nil, errors.Errorf("%s is not a valid hostname", userHostname)
	}
	return cfapi.NewDNSRoute(userHostname, overwriteExisting), nil
}

func lbRouteFromArg(c *cli.Context) (cfapi.HostnameRoute, error) {
	const (
		lbNameIndex   = 1
		lbPoolIndex   = 2
		expectedNArgs = 3
	)
	if c.NArg() != expectedNArgs {
		return nil, cliutil.UsageError("Expected %d arguments, got %d", expectedNArgs, c.NArg())
	}
	lbName := c.Args().Get(lbNameIndex)
	if lbName == "" {
		return nil, cliutil.UsageError("The third argument should be the load balancer name")
	} else if !validateHostname(lbName, true) {
		return nil, errors.Errorf("%s is not a valid load balancer name", lbName)

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Pass a bare hostname/FQDN without scheme, path, or port: `app.example.com`.
  2. Place wildcards only at the start if allowed: `*.example.com`.
  3. Ensure the hostname belongs to a zone in your Cloudflare account so DNS routing can succeed.
  4. Check for hidden characters/typos; retype the hostname.

Example fix

// before
cloudflared tunnel route dns my-tunnel https://app.example.com:8080
// after
cloudflared tunnel route dns my-tunnel app.example.com
Defensive patterns

Strategy: validation

Validate before calling

// Go: check the hostname argument before calling `tunnel route dns`
import "net"
func validHostnameArg(h string) bool {
	if h == "" || strings.ContainsAny(h, ":/@ ") {
		return false
	}
	if net.ParseIP(h) != nil {
		return false
	}
	labels := strings.Split(strings.TrimPrefix(h, "*."), ".")
	return len(labels) >= 2
}

Prevention

When it happens

Trigger: Running `cloudflared tunnel route dns <tunnel> <hostname>` where the third argument contains invalid characters, is not a valid domain (e.g. includes a scheme, path, underscore, port), is an IP address, or has a misplaced wildcard like `sub.*.example.com`.

Common situations: Passing a full URL (https://app.example.com) instead of a bare hostname, including a port (:8080), using a subdomain-only value (app) without a zone, or wildcard notation in the wrong position.

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/8b7f8e2d8bc0613f. Report an issue: GitHub.