{"record":{"id":"c61ebf9892a97f13","repo":"caddyserver/caddy","slug":"compiling-regular-expression-d-v","errorCode":null,"errorMessage":"compiling regular expression %d: %v","messagePattern":"compiling regular expression (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/rewrite/rewrite.go","lineNumber":116,"sourceCode":"// CaddyModule returns the Caddy module information.\nfunc (Rewrite) CaddyModule() caddy.ModuleInfo {\n\treturn caddy.ModuleInfo{\n\t\tID:  \"http.handlers.rewrite\",\n\t\tNew: func() caddy.Module { return new(Rewrite) },\n\t}\n}\n\n// Provision sets up rewr.\nfunc (rewr *Rewrite) Provision(ctx caddy.Context) error {\n\trewr.logger = ctx.Logger()\n\n\tfor i, rep := range rewr.PathRegexp {\n\t\tif rep.Find == \"\" {\n\t\t\treturn fmt.Errorf(\"path_regexp find cannot be empty\")\n\t\t}\n\t\tre, err := regexp.Compile(rep.Find)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"compiling regular expression %d: %v\", i, err)\n\t\t}\n\t\trep.re = re\n\t}\n\tif rewr.Query != nil {\n\t\tfor _, replacementOp := range rewr.Query.Replace {\n\t\t\terr := replacementOp.Provision(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"compiling regular expression %s in query rewrite replace operation: %v\", replacementOp.SearchRegexp, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {\n\trepl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)\n\tconst message = \"rewrote request\"","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/rewrite/rewrite.go#L98-L134","documentation":"The rewrite handler compiles each path_regexp pattern with Go's regexp.Compile at provision time; this error wraps a compile failure and includes the 0-based index of the offending entry. Go's RE2 syntax differs from PCRE, so patterns valid in nginx or Perl (backreferences, lookaheads) fail here. The error is fatal at config load.","triggerScenarios":"A path_regexp 'find' containing invalid RE2 syntax: unbalanced parentheses like \"(/old\", bad escapes like \"\\d+\" written as \"\\d+\" in JSON without proper quoting, or PCRE-only constructs like \"(?=foo)\" or \"(a)\\1\".","commonSituations":"Porting nginx rewrite rules (lookaheads/backreferences) to Caddy, JSON escaping mistakes where the regex loses its backslashes, or using { } quantifiers that clash with Caddy placeholder syntax without escaping.","solutions":["Read the wrapped regexp error — it names the exact syntax problem and position","Replace PCRE-only constructs: drop lookaheads/backreferences, rewrite with capture groups used via {re.match.1} placeholders","Double-check backslash escaping in JSON/Caddyfile (\"\\\\d\" in JSON for \\d)","Test the pattern standalone: echo 'pattern' in Go regexp tester or 'go run' a snippet with regexp.Compile"],"exampleFix":"// before\n\"path_regexp\": [{ \"find\": \"/old(/\", \"replace\": \"/new\" }]\n\n// after\n\"path_regexp\": [{ \"find\": \"/old(/\", \"replace\": \"/new\" }]  // balanced: \"/old(/\" -> \"/old(/\" \n// concretely: \"find\": \"/old/(.*)\", \"replace\": \"/new/{re.match.1}\"","handlingStrategy":"validation","validationCode":"for i, rep := range rewriteCfg.PathRegexp {\n    if _, err := regexp.Compile(rep.Find); err != nil {\n        return fmt.Errorf(\"path_regexp[%d] has invalid regex %q: %w\", i, rep.Find, err)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Test regexes with Go (RE2) semantics, not PCRE testers","Remember lookaheads, lookbehinds and backreferences are unsupported","Escape backslashes correctly for JSON (double them)"],"tags":["caddy","regex","rewrite","config","re2"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}