caddyserver/caddy · error
matcher module '%s' is not a request matcher
Error message
matcher module '%s' is not a request matcher
What it means
The named-matcher closure requires the unmarshaled module to be usable as an HTTP request matcher: it must implement either caddyhttp.RequestMatcherWithError or the deprecated caddyhttp.RequestMatcher. If it implements neither, it cannot be placed in a matcher set and adapt fails. Like error 141 this points to a plugin implementing the wrong (e.g. response-matcher or middleware) interface.
Source
Thrown at caddyconfig/httpcaddyfile/httptype.go:1715
unm, ok := mod.New().(caddyfile.Unmarshaler)
if !ok {
return fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
}
err = unm.UnmarshalCaddyfile(dispenser)
if err != nil {
return err
}
if rm, ok := unm.(caddyhttp.RequestMatcherWithError); ok {
matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
return nil
}
// nolint:staticcheck
if rm, ok := unm.(caddyhttp.RequestMatcher); ok {
matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
return nil
}
return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
}
// if the next token is quoted, we can assume it's not a matcher name
// and that it's probably an 'expression' matcher
if d.NextArg() {
if d.Token().Quoted() {
// since it was missing the matcher name, we insert a token
// in front of the expression token itself; we use Clone() to
// make the new token to keep the same the import location as
// the next token, if this is within a snippet or imported file.
// see https://github.com/caddyserver/caddy/issues/6287
expressionToken := d.Token().Clone()
expressionToken.Text = "expression"
err := makeMatcher("expression", []caddyfile.Token{expressionToken, d.Token()})
if err != nil {
return err
}
return nilView on GitHub (pinned to 50e54ee279)
Solutions
- If you own the module: implement 'Match(r *http.Request) (bool, error)' (RequestMatcherWithError) on the matcher type and add a compile-time guard.
- If not: rebuild with a plugin version matched to your Caddy release.
- Check 'caddy list-modules' to confirm which module ID resolves to the name and whether it belongs in http.matchers.
- Use the JSON config to confirm the module's supported roles if the Caddyfile path keeps failing.
Example fix
// after (add to the matcher type)
func (m MatchThing) Match(r *http.Request) (bool, error) {
return r.URL.Path == m.Value, nil
}
var _ caddyhttp.RequestMatcherWithError = (*MatchThing)(nil) Defensive patterns
Strategy: type-guard
Type guard
var _ caddyhttp.RequestMatcherWithError = (*MatchThing)(nil)
Prevention
- Distinguish request matchers from response matchers when authoring plugins; only the former may appear in named matchers.
- Use compile-time guards in CI builds of custom plugins.
- Prefer RequestMatcherWithError over the deprecated RequestMatcher.
When it happens
Trigger: A module registered in 'http.matchers.' that actually implements caddyhttp.ResponseMatcher or only caddy.Module; custom matchers built against pre-2.7 APIs without MatchWithError; trying to use a response-matcher-only module as a named request matcher.
Common situations: Plugin upgrade/downgrade mismatches with the Caddy core version; plugin authors forgetting that named matchers must satisfy the request-matcher interface; users attempting to use handler modules in matcher position.
Related errors
- matcher module '%s' is not a Caddyfile unmarshaler
- marshaling matcher set %#v: %v
- matcher module '%s' is not a request matcher
- getting matcher module '%s': %v
- module %s (%T) is not a listener wrapper
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/4149dd65455d7dbf.
Report an issue: GitHub.