valyala/fasthttp · error
invalid host %q: use a host client for multiple hosts
Error message
invalid host %q: use a host client for multiple hosts
What it means
The generic fasthttp Client routes requests to per-host HostClients created on demand. A URI whose host contains a comma cannot map to a single host, so Do rejects it and tells you to use a HostClient bound to a specific host instead.
Source
Thrown at client.go:550
// Response is ignored if resp is nil.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// ErrNoFreeConns is returned if all Client.MaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *Client) Do(req *Request, resp *Response) error {
uri := req.URI()
if uri == nil {
return ErrorInvalidURI
}
host := uri.Host()
if bytes.ContainsRune(host, ',') {
return fmt.Errorf("invalid host %q: use a host client for multiple hosts", host)
}
isTLS := false
if uri.isHTTPS() {
isTLS = true
} else if !uri.isHTTP() {
return fmt.Errorf("unsupported protocol %q. http and https are supported", uri.Scheme())
}
c.mOnce.Do(func() {
c.m = make(map[string]*HostClient)
c.ms = make(map[string]*HostClient)
})
hc, err := c.hostClient(host, isTLS)
if err != nil {
return err
}
View on GitHub (pinned to c96f600972)
Solutions
- Use fasthttphost-style HostClient with c.Host set explicitly, or fasthttp.HostClient{Addr: ...} per target
- Split the comma-joined value and pick/iterate one host per request
- Sanitize or reject comma characters when constructing URIs from user input
- Fix the code path that interpolates a Host header or config list directly into the URL
Example fix
// before
req.SetRequestURI("http://" + strings.Join(backends, ",") + "/api")
client.Do(req, resp)
// after
hc := &fasthttp.HostClient{Addr: pickBackend(backends)}
req.SetRequestURI("http://" + hc.Addr + "/api")
hc.Do(req, resp) Defensive patterns
Strategy: validation
Validate before calling
u, _ := url.Parse(req.URI().String())
if strings.Contains(u.Host, ",") { return errors.New("multiple hosts in URI; use HostClient") } Type guard
func isSingleHostURI(uri string) bool {
u, err := url.Parse(uri)
return err == nil && !strings.Contains(u.Host, ",")
} Try / catch
err := client.Do(req, resp)
if err != nil {
if strings.Contains(err.Error(), "use a host client for multiple hosts") {
// fall back to a per-host HostClient
}
} Prevention
- Never join multiple backends with commas into one URL
- Create one fasthttp.HostClient per upstream host
- Sanitize Host headers copied from inbound requests
When it happens
Trigger: Calling client.Do/DoTimeout/DoDeadline with a request whose RequestURI/URL host contains ',', e.g. "http://host1,host2/path" or a comma-joined host list copied from a proxy config or Host header.
Common situations: Building a URL by joining multiple backends with commas, reusing a Host header from an inbound request that contained a comma list, load-balancer-style config pasted into the URL.
Related errors
- unsupported protocol %q. http and https are supported
- must implement readat
- directory index required
- no 'create file' permissions
- seek is not implemented
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/24714654d56a9a24.
Report an issue: GitHub.