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
- Set the --destination flag on the client command, e.g. `cloudflared access ssh --hostname bastion.example.com --destination internal-host:22`.
- Upgrade the client cloudflared to a version that sends the Cf-Jump-Target-Destination header.
- Ensure intermediate proxies/WAF rules do not strip Cf-Jump-* headers from the request.
- 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
- Always pass --destination when using `cloudflared access ssh`/tcp in bastion mode
- Pin matching client and server cloudflared versions
- Verify proxies preserve Cf-Jump-* custom headers
- Test the bastion route with a known-good command before scripting it
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
- tunnelCmdErrorMessage
- No configuration file was found. Please create one, or use t
- --metrics has to be provided
- ErrNoIngressRulesCLI
- configuration file %s must contain entries for the tunnel to
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/6e077f1279131daa.
Report an issue: GitHub.