{"record":{"id":"4d2db22aced5ab0e","repo":"caddyserver/caddy","slug":"matcher-module-s-is-not-a-request-matcher-4d2db2","errorCode":null,"errorMessage":"matcher module '%s' is not a request matcher","messagePattern":"matcher module '(.+?)' is not a request matcher","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/matchers.go","lineNumber":1720,"sourceCode":"\t\t\treturn nil, d.Errf(\"getting matcher module '%s': %v\", matcherName, err)\n\t\t}\n\t\tunm, ok := mod.New().(caddyfile.Unmarshaler)\n\t\tif !ok {\n\t\t\treturn nil, d.Errf(\"matcher module '%s' is not a Caddyfile unmarshaler\", matcherName)\n\t\t}\n\t\terr = unm.UnmarshalCaddyfile(caddyfile.NewDispenser(tokens))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif rm, ok := unm.(RequestMatcherWithError); ok {\n\t\t\tmatcherMap[matcherName] = rm\n\t\t\tcontinue\n\t\t}\n\t\tif rm, ok := unm.(RequestMatcher); ok {\n\t\t\tmatcherMap[matcherName] = rm\n\t\t\tcontinue\n\t\t}\n\t\treturn nil, fmt.Errorf(\"matcher module '%s' is not a request matcher\", matcherName)\n\t}\n\n\t// we should now have a functional matcher, but we also\n\t// need to be able to marshal as JSON, otherwise config\n\t// adaptation will be missing the matchers!\n\tmatcherSet := make(caddy.ModuleMap)\n\tfor name, matcher := range matcherMap {\n\t\tjsonBytes, err := json.Marshal(matcher)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"marshaling %T matcher: %v\", matcher, err)\n\t\t}\n\t\tmatcherSet[name] = jsonBytes\n\t}\n\n\treturn matcherSet, nil\n}\n\nvar wordRE = regexp.MustCompile(`\\w+`)","sourceCodeStart":1702,"sourceCodeEnd":1738,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/matchers.go#L1702-L1738","documentation":"While parsing Caddyfile named-matcher definitions (parseMatcherDefinitions), each token is unmarshalled via its module's UnmarshalCaddyfile and then asserted to RequestMatcher/RequestMatcherWithError. A matcher name that resolves to a module not implementing those interfaces produces this error. This is the Caddyfile-adaptation path, so it surfaces at `caddy adapt`/`validate` time.","triggerScenarios":"Writing @m not { ... } style nested tokens incorrectly, using an undefined/misspelled matcher name inside a named matcher, or a third-party plugin registering under http.matchers.* a type that is not a request matcher.","commonSituations":"Typos in matcher names (`path_regexpx`); plugins built against an old Caddy API where the module was a handler but named like a matcher; custom forks with namespace mistakes.","solutions":["Correct the matcher token to a real request matcher (path, host, method, header, query, path_regexp, ...).","If it comes from a plugin, ensure the plugin type implements RequestMatcher/RequestMatcherWithError and is registered under http.matchers.*.","Run `caddy adapt --pretty --config Caddyfile` to localize the failing token."],"exampleFix":"// before (Caddyfile)\n@m path_regexpx ^/api\n\n// after\n@m path_regexp ^/api","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Verify a module instance is usable as a Caddyfile named matcher\nfunc isRequestMatcher(mod caddy.Module) bool {\n\tif _, ok := mod.(caddyhttp.RequestMatcherWithError); ok {\n\t\treturn true\n\t}\n\t_, ok := mod.(caddyhttp.RequestMatcher)\n\treturn ok\n}","tryCatchPattern":null,"preventionTips":["Spell matcher tokens exactly (path_regexp, header_regexp, query_regexp).","Run `caddy adapt --pretty` to localize failing tokens early.","Keep plugins in the build; missing modules surface here."],"tags":["caddy","caddyfile","matcher","plugin","adaptation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}