{"record":{"id":"00ef52d0bec4bff6","repo":"caddyserver/caddy","slug":"unrecognized-matcher-name-v","errorCode":null,"errorMessage":"unrecognized matcher name: %+v","messagePattern":"unrecognized matcher name: %\\+v","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"caddyconfig/httpcaddyfile/httptype.go","lineNumber":1587,"sourceCode":"\t// matcher tokens can be wildcards, simple path matchers,\n\t// or refer to a pre-defined matcher by some name\n\tif tkn.Text == \"*\" {\n\t\t// match all requests == no matchers, so nothing to do\n\t\treturn nil, true, nil\n\t}\n\n\t// convenient way to specify a single path match\n\tif strings.HasPrefix(tkn.Text, \"/\") {\n\t\treturn caddy.ModuleMap{\n\t\t\t\"path\": caddyconfig.JSON(caddyhttp.MatchPath{tkn.Text}, warnings),\n\t\t}, true, nil\n\t}\n\n\t// pre-defined matcher\n\tif strings.HasPrefix(tkn.Text, matcherPrefix) {\n\t\tm, ok := matcherDefs[tkn.Text]\n\t\tif !ok {\n\t\t\treturn nil, false, fmt.Errorf(\"unrecognized matcher name: %+v\", tkn.Text)\n\t\t}\n\t\treturn m, true, nil\n\t}\n\n\treturn nil, false, nil\n}\n\nfunc (st *ServerType) compileEncodedMatcherSets(sblock serverBlock) ([]caddy.ModuleMap, error) {\n\ttype hostPathPair struct {\n\t\thostm caddyhttp.MatchHost\n\t\tpathm caddyhttp.MatchPath\n\t}\n\n\t// keep routes with common host and path matchers together\n\tvar matcherPairs []*hostPathPair\n\n\tvar catchAllHosts bool\n\tfor _, addr := range sblock.parsedKeys {","sourceCodeStart":1569,"sourceCodeEnd":1605,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/caddyconfig/httpcaddyfile/httptype.go#L1569-L1605","documentation":"A token starting with `@` (the named-matcher prefix) was referenced in a directive's matcher position, but no matcher with that name was defined in the current server block. Named matchers must be declared with `@name ...` inside the same site block before use.","triggerScenarios":"Writing `respond @foo 200` (or `reverse_proxy @api ...`) where `@foo` was never declared, declaring the matcher in a different site block than where it is referenced, or a typo such as `@apistatus` vs `@apistaus`. parseSegmentAsSubroute -> matcher token parsing hits matcherDefs lookup failure.","commonSituations":"Renaming a matcher and missing a usage site; expecting named matchers to be global when they are per-site-block; snippets referencing matchers the importing block does not define (use `import` of the matcher definition too).","solutions":["Define the named matcher at the top of the same site block: `@foo path /foo*`","Fix the typo so the reference matches the definition exactly (including the @)","If the matcher lives in a snippet, import the snippet that defines it into the same block","Move the shared matcher definition into each site block that uses it"],"exampleFix":"# before\nexample.com {\n  @api path /api/*\n  reverse_proxy @backend localhost:9000  # @backend not defined\n}\n# after\nexample.com {\n  @api path /api/*\n  reverse_proxy @api localhost:9000\n}","handlingStrategy":"validation","validationCode":"# Collect matcher definitions per block before adapting\nfor block in blocks:\n    defined = {m.name for m in block.matcher_defs}\n    for ref in block.matcher_refs:\n        assert ref in defined, f'undefined matcher {ref} in {block.key}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Define named matchers at the top of the same site block","Keep one canonical spelling; grep @name usages after renames","Remember matchers are block-scoped — snippets must define what they reference"],"tags":["caddy","caddyfile","matchers","typo"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}