caddyserver/caddy · error
invalid upstream address %s: %v
Error message
invalid upstream address %s: %v
What it means
One of the --to upstream values failed parseUpstreamDialAddress while the command was normalizing upstream addresses. This is the CLI equivalent of the Caddyfile upstream parse errors: scheme+placeholder conflicts, bad ports, paths in URLs, or scheme/port conflicts, surfaced under 'invalid upstream address %s'.
Source
Thrown at modules/caddyhttp/reverseproxy/command.go:140
}
}
if fromAddr.Port == "" {
switch fromAddr.Scheme {
case "http":
fromAddr.Port = httpPort
case "https":
fromAddr.Port = httpsPort
}
}
// set up the upstream address; assume missing information from given parts
// mixing schemes isn't supported, so use first defined (if available)
toAddresses := make([]string, len(to))
var toScheme string
for i, toLoc := range to {
addr, err := parseUpstreamDialAddress(toLoc)
if err != nil {
return caddy.ExitCodeFailedStartup, fmt.Errorf("invalid upstream address %s: %v", toLoc, err)
}
if addr.scheme != "" && toScheme == "" {
toScheme = addr.scheme
}
toAddresses[i] = addr.dialAddr()
}
// proceed to build the handler and server
ht := HTTPTransport{}
if toScheme == "https" {
ht.TLS = new(TLSConfig)
if insecure {
ht.TLS.InsecureSkipVerify = true
}
}
upstreamPool := UpstreamPool{}
for _, toAddr := range toAddresses {View on GitHub (pinned to 50e54ee279)
Solutions
- Fix the named upstream per the underlying error: host[:port] or scheme://host[:port] only.
- Move path rewriting into a Caddyfile (rewrite + reverse_proxy) instead of the quick command.
- Re-run with a minimal known-good --to like 'localhost:8080' to confirm the rest of the command works.
Example fix
# before caddy reverse-proxy --from example.com --to http://backend:9000/api # after caddy reverse-proxy --from example.com --to http://backend:9000
Defensive patterns
Strategy: validation
Validate before calling
for _, t := range toValues {
if strings.Contains(t, "://") {
if strings.Contains(t, "{") {
return fmt.Errorf("--to %q: placeholders not allowed with a scheme", t)
}
if u, err := url.Parse(t); err != nil || u.Path != "" || u.RawQuery != "" || u.Fragment != "" {
return fmt.Errorf("--to %q must be scheme://host[:port] only", t)
}
}
} Prevention
- Use bare host:port for --to and enable TLS via flags/config, not URL decoration.
- Do path rewriting in a Caddyfile, not the quick command.
- Smoke-test with --to localhost:8080 before complex backends.
When it happens
Trigger: 'caddy reverse-proxy --from x --to https://{env.H}', '--to http://host/path', '--to http://host:443', or any dial-address syntax violation from the parseUpstreamDialAddress rules.
Common situations: First-time users pasting full backend URLs with paths; env-var-driven deployments attempting placeholders in the scheme-bearing address.
Related errors
- invalid to flag: %v
- --to is required
- invalid downstream address %s: %v
- paths are not allowed: %s
- invalid header flag: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/715a50430bc47c6d.
Report an issue: GitHub.