caddyserver/caddy · error
invalid header flag: %v
Error message
invalid header flag: %v
What it means
Thrown by the `caddy reverse-proxy` CLI command when the `--header-up` flag value cannot be read as a string array by pflag. This is a flag-parsing failure, not a header-format failure: the command line argument itself was malformed for the flag library. Caddy aborts startup with ExitCodeFailedStartup.
Source
Thrown at modules/caddyhttp/reverseproxy/command.go:187
} else {
// expand a port range into multiple upstreams
for i := parsedAddr.StartPort; i <= parsedAddr.EndPort; i++ {
upstreamPool = append(upstreamPool, &Upstream{
Dial: caddy.JoinNetworkAddress("", parsedAddr.Host, fmt.Sprint(i)),
})
}
}
}
handler := Handler{
TransportRaw: caddyconfig.JSONModuleObject(ht, "protocol", "http", nil),
Upstreams: upstreamPool,
}
// set up header_up
headerUp, err := fs.GetStringArray("header-up")
if err != nil {
return caddy.ExitCodeFailedStartup, fmt.Errorf("invalid header flag: %v", err)
}
if len(headerUp) > 0 {
reqHdr := make(http.Header)
for i, h := range headerUp {
key, val, found := strings.Cut(h, ":")
key, val = strings.TrimSpace(key), strings.TrimSpace(val)
if !found || key == "" || val == "" {
return caddy.ExitCodeFailedStartup, fmt.Errorf("header-up %d: invalid format \"%s\" (expecting \"Field: value\")", i, h)
}
reqHdr.Set(key, val)
}
handler.Headers = &headers.Handler{
Request: &headers.HeaderOps{
Set: reqHdr,
},
}
}
View on GitHub (pinned to 50e54ee279)
Solutions
- Check the exact spelling and casing of --header-up against `caddy reverse-proxy --help` output for your binary
- Quote each header argument fully in shell scripts: --header-up "Field: value"
- Verify you are not mixing --header-up with deprecated or renamed flags from an older Caddy version
- Print the command as executed (e.g. `set -x` in bash) to see what the shell actually passed
Example fix
# before caddy reverse-proxy --to localhost:9000 --header-up Host:example.com X-Custom:1 # after caddy reverse-proxy --to localhost:9000 --header-up "Host: example.com" --header-up "X-Custom: 1"
Defensive patterns
Strategy: validation
Validate before calling
# before invoking, assert the flag parses as a repeated string array if ! grep -qE -- '--header-up[= ]+[^ ].*' <<< "$*"; then echo "bad --header-up"; exit 1; fi # simplest: always pass quoted "Field: value" pairs and check exit code of caddy
Try / catch
cmd := exec.Command("caddy", "reverse-proxy", "--to", to)
if out, err := cmd.CombinedOutput(); err != nil {
log.Printf("reverse-proxy failed: %v\n%s", err, out)
os.Exit(1)
} Prevention
- Quote every header flag value in shell scripts
- Pin the Caddy version in deployment scripts so flag surface does not drift
- Prefer a Caddyfile over ad-hoc CLI flags for anything non-trivial
When it happens
Trigger: Running `caddy reverse-proxy --header-up ...` with a flag value pflag cannot interpret as a StringArray (e.g. the flag was already consumed as a different type, or a custom flag set misregistered the option). The source calls `fs.GetStringArray("header-up")` and any error from it is wrapped here.
Common situations: Typos in the flag name, using `=` vs space forms inconsistently, scripting the command with unquoted shell expansions that collapse or drop values, or version drift between Caddy releases that changed flag registration.
Related errors
- invalid to flag: %v
- --to is required
- invalid downstream address %s: %v
- paths are not allowed: %s
- invalid upstream address %s: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/979aa8a03627bf52.
Report an issue: GitHub.