cloudflare/cloudflared · error

Did not receive final destination from client. The --destina

Error message

Did not receive final destination from client. The --destination flag is likely not set on the client side

What it means

carrier.ResolveBastionDest reads the Cf-Jump-Target-Destination header that the cloudflared client sets when using bastion mode (`cloudflared access ssh --destination ...`). If the header is empty, the edge/carrier side cannot know which final host to jump to and returns this error. It is a client configuration problem, not a server fault.

Source

Thrown at carrier/carrier.go:174

	for k, v := range options.Headers {
		if len(v) >= 1 {
			originRequest.Header.Set(k, v[0])
		}
	}

	return originRequest, nil
}

func SetBastionDest(header http.Header, destination string) {
	if destination != "" {
		header.Set(cfJumpDestinationHeader, destination)
	}
}

func ResolveBastionDest(r *http.Request) (string, error) {
	jumpDestination := r.Header.Get(cfJumpDestinationHeader)
	if jumpDestination == "" {
		return "", fmt.Errorf("Did not receive final destination from client. The --destination flag is likely not set on the client side")
	}
	// Strip scheme and path set by client. Without a scheme
	// Parsing a hostname and path without scheme might not return an error due to parsing ambiguities
	if jumpURL, err := url.Parse(jumpDestination); err == nil && jumpURL.Host != "" {
		return removePath(jumpURL.Host), nil
	}
	return removePath(jumpDestination), nil
}

func removePath(dest string) string {
	return strings.SplitN(dest, "/", 2)[0]
}

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Set the --destination flag on the client command, e.g. `cloudflared access ssh --hostname bastion.example.com --destination internal-host:22`.
  2. Upgrade the client cloudflared to a version that sends the Cf-Jump-Target-Destination header.
  3. Ensure intermediate proxies/WAF rules do not strip Cf-Jump-* headers from the request.
  4. If resolving the destination from access rules (getDestFromRule), configure the rule's destination so a value exists.

Example fix

// before
cloudflared access ssh --hostname bastion.example.com
// after
cloudflared access ssh --hostname bastion.example.com --destination internal-server.internal:22
Defensive patterns

Strategy: validation

Validate before calling

// client side, before opening the bastion session
if destination == "" {
    return fmt.Errorf("--destination is required in bastion mode, e.g. --destination host:22")
}

Try / catch

dest, err := carrier.ResolveBastionDest(req)
if err != nil {
    http.Error(w, err.Error(), http.StatusBadRequest)
    return
}

Prevention

When it happens

Trigger: ResolveBastionDest(r) is called on an incoming websocket request in bastion mode and r.Header.Get(cfJumpDestinationHeader) returns "" — i.e. the request arrived without the jump-destination header because the client did not send one.

Common situations: User runs `cloudflared access ssh` or TCP-over-WS without the --destination flag (or with an empty value); an older client version that doesn't send the header connecting to a newer server; a proxy/load balancer stripping custom Cf-* headers; hitting the bastion URL with a plain HTTP client instead of `cloudflared access`.

Understand the failure class

Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.

Related errors


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