caddyserver/caddy · error

header-up : invalid format " " (expecting "Field: value")

Error message

header-up %d: invalid format "%s" (expecting "Field: value")

What it means

The `caddy reverse-proxy` command validates each `--header-up` value as `"Field: value"`. The string is split on the first colon with `strings.Cut`; if no colon is found, or either side is empty after trimming whitespace, Caddy exits with this error naming the offending index and raw string.

Solutions

  1. Rewrite the flag value as "Field: value" with both sides non-empty
  2. If the value comes from an environment variable, verify it is set before launching the command
  3. Check the index reported in the message (0-based) against the Nth --header-up argument to find the bad one

Example fix

# before
caddy reverse-proxy --to localhost:9000 --header-up "X-Forwarded-Proto"
# after
caddy reverse-proxy --to localhost:9000 --header-up "X-Forwarded-Proto: https"
Defensive patterns

Strategy: validation

Validate before calling

func validHeaderFlag(s string) bool {
	key, val, found := strings.Cut(s, ":")
	return found && strings.TrimSpace(key) != "" && strings.TrimSpace(val) != ""
}

for i, h := range headerUps {
	if !validHeaderFlag(h) {
		log.Fatalf("header-up %d invalid: %q", i, h)
	}
}

Prevention

When it happens

Trigger: Passing `--header-up "X-Foo"` (no colon), `--header-up ": value"` (empty field name), `--header-up "X-Foo: "` (empty value), or `--header-up "X-Foo:"` (empty value after trim).

Common situations: Forgetting the colon separator, adding a trailing colon with no value, or a shell variable that expands to an empty string, e.g. `--header-up "X-Api-Key: $KEY"` when $KEY is unset in the environment.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/62b9133e69edc785. Report an issue: GitHub.

Appendix: source

Thrown at modules/caddyhttp/reverseproxy/command.go:195

	}

	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,
			},
		}
	}

	// set up header_down
	headerDown, err := fs.GetStringArray("header-down")
	if err != nil {
		return caddy.ExitCodeFailedStartup, fmt.Errorf("invalid header flag: %v", err)
	}
	if len(headerDown) > 0 {
		respHdr := make(http.Header)
		for i, h := range headerDown {

View on GitHub (pinned to 50e54ee279)