{"record":{"id":"62b9133e69edc785","repo":"caddyserver/caddy","slug":"header-up-d-invalid-format-s-expecting-fiel","errorCode":null,"errorMessage":"header-up %d: invalid format \"%s\" (expecting \"Field: value\")","messagePattern":"header-up (.+?): invalid format \"(.+?)\" \\(expecting \"Field: value\"\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/reverseproxy/command.go","lineNumber":195,"sourceCode":"\t}\n\n\thandler := Handler{\n\t\tTransportRaw: caddyconfig.JSONModuleObject(ht, \"protocol\", \"http\", nil),\n\t\tUpstreams:    upstreamPool,\n\t}\n\n\t// set up header_up\n\theaderUp, err := fs.GetStringArray(\"header-up\")\n\tif err != nil {\n\t\treturn caddy.ExitCodeFailedStartup, fmt.Errorf(\"invalid header flag: %v\", err)\n\t}\n\tif len(headerUp) > 0 {\n\t\treqHdr := make(http.Header)\n\t\tfor i, h := range headerUp {\n\t\t\tkey, val, found := strings.Cut(h, \":\")\n\t\t\tkey, val = strings.TrimSpace(key), strings.TrimSpace(val)\n\t\t\tif !found || key == \"\" || val == \"\" {\n\t\t\t\treturn caddy.ExitCodeFailedStartup, fmt.Errorf(\"header-up %d: invalid format \\\"%s\\\" (expecting \\\"Field: value\\\")\", i, h)\n\t\t\t}\n\t\t\treqHdr.Set(key, val)\n\t\t}\n\t\thandler.Headers = &headers.Handler{\n\t\t\tRequest: &headers.HeaderOps{\n\t\t\t\tSet: reqHdr,\n\t\t\t},\n\t\t}\n\t}\n\n\t// set up header_down\n\theaderDown, err := fs.GetStringArray(\"header-down\")\n\tif err != nil {\n\t\treturn caddy.ExitCodeFailedStartup, fmt.Errorf(\"invalid header flag: %v\", err)\n\t}\n\tif len(headerDown) > 0 {\n\t\trespHdr := make(http.Header)\n\t\tfor i, h := range headerDown {","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/reverseproxy/command.go#L177-L213","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Rewrite the flag value as \"Field: value\" with both sides non-empty","If the value comes from an environment variable, verify it is set before launching the command","Check the index reported in the message (0-based) against the Nth --header-up argument to find the bad one"],"exampleFix":"# before\ncaddy reverse-proxy --to localhost:9000 --header-up \"X-Forwarded-Proto\"\n# after\ncaddy reverse-proxy --to localhost:9000 --header-up \"X-Forwarded-Proto: https\"","handlingStrategy":"validation","validationCode":"func validHeaderFlag(s string) bool {\n\tkey, val, found := strings.Cut(s, \":\")\n\treturn found && strings.TrimSpace(key) != \"\" && strings.TrimSpace(val) != \"\"\n}\n\nfor i, h := range headerUps {\n\tif !validHeaderFlag(h) {\n\t\tlog.Fatalf(\"header-up %d invalid: %q\", i, h)\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adopt the \"Field: value\" shape as a convention in scripts","Fail fast in CI on empty env vars used inside header flags: test -n \"$KEY\""],"tags":["cli","reverse-proxy","headers","validation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}