{"record":{"id":"cd196f5ce9331d88","repo":"caddyserver/caddy","slug":"expect-body-compiling-regular-expression-v","errorCode":null,"errorMessage":"expect_body: compiling regular expression: %v","messagePattern":"expect_body: compiling regular expression: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/reverseproxy/healthchecks.go","lineNumber":209,"sourceCode":"\t\t// then the port is ignored.\n\t\tif a.Upstream != \"\" {\n\t\t\tupstream.activeHealthCheckUpstream = a.Upstream\n\t\t} else if a.Port != 0 {\n\t\t\t// if there's an alternative port for health-check provided in the config,\n\t\t\t// then use it, otherwise use the port of upstream.\n\t\t\tupstream.activeHealthCheckPort = a.Port\n\t\t}\n\t}\n\n\tif a.Interval == 0 {\n\t\ta.Interval = caddy.Duration(30 * time.Second)\n\t}\n\n\tif a.ExpectBody != \"\" {\n\t\tvar err error\n\t\ta.bodyRegexp, err = regexp.Compile(a.ExpectBody)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"expect_body: compiling regular expression: %v\", err)\n\t\t}\n\t}\n\n\tif a.Passes < 1 {\n\t\ta.Passes = 1\n\t}\n\n\tif a.Fails < 1 {\n\t\ta.Fails = 1\n\t}\n\n\treturn nil\n}\n\n// IsEnabled checks if the active health checks have\n// the minimum config necessary to be enabled.\nfunc (a *ActiveHealthChecks) IsEnabled() bool {\n\treturn a.Path != \"\" || a.URI != \"\" || a.Port != 0","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/reverseproxy/healthchecks.go#L191-L227","documentation":"During provisioning of active health checks, the `expect_body` value is compiled as a Go regexp (`regexp.Compile`). If the pattern is invalid Go regexp syntax, provisioning fails with the underlying compile error, and the reverse_proxy module (and the whole config load) errors out.","triggerScenarios":"Setting `health_uri`-style active checks with `expect_body` to a string with invalid Go regex syntax: unbalanced parens, trailing backslash, invalid character class like `[z-a]`, or PCRE-only constructs like lookaheads `(?=...)`.","commonSituations":"Porting regexes from nginx/PCRE or JavaScript that use lookaheads/lookbehinds (unsupported in Go's RE2); unescaped braces intended literally, e.g. matching JSON bodies like `{\"status\":\"ok\"}`.","solutions":["Test the pattern with a Go regexp tool or `go run` snippet before putting it in config","Remove PCRE-only features (lookahead/lookbehind/backreferences) — Go RE2 does not support them","Escape literal braces and dots: \\{ \\. e.g. expect_body \"status.*ok\"","Simplify to a substring that is plain text, since expect_body only needs to match part of the body"],"exampleFix":"# before\nreverse_proxy localhost:9000 {\n\thealth_uri /health\n\texpect_body \"{\\\"status\\\":\\\"ok\\\"}\"\n}\n# after\nreverse_proxy localhost:9000 {\n\thealth_uri /health\n\texpect_body \"status\":\"ok\"\n}","handlingStrategy":"validation","validationCode":"if health.ExpectBody != \"\" {\n\tif _, err := regexp.Compile(health.ExpectBody); err != nil {\n\t\treturn fmt.Errorf(\"expect_body invalid: %w\", err)\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Test regexes with Go's regexp package (RE2) — not PCRE — before config rollout","Prefer plain substrings over regexes for expect_body when possible","Escape literal { } . in JSON health-check bodies"],"tags":["reverse-proxy","health-check","regex","validation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}