{"record":{"id":"430d12c83c5b0f04","repo":"caddyserver/caddy","slug":"loading-matcher-sets-v","errorCode":null,"errorMessage":"loading matcher sets: %v","messagePattern":"loading matcher sets: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/matchers.go","lineNumber":1522,"sourceCode":"}\n\n// UnmarshalJSON satisfies json.Unmarshaler. It puts the JSON\n// bytes directly into m's MatcherSetsRaw field.\nfunc (m *MatchNot) UnmarshalJSON(data []byte) error {\n\treturn json.Unmarshal(data, &m.MatcherSetsRaw)\n}\n\n// MarshalJSON satisfies json.Marshaler by marshaling\n// m's raw matcher sets.\nfunc (m MatchNot) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(m.MatcherSetsRaw)\n}\n\n// Provision loads the matcher modules to be negated.\nfunc (m *MatchNot) Provision(ctx caddy.Context) error {\n\tmatcherSets, err := ctx.LoadModule(m, \"MatcherSetsRaw\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"loading matcher sets: %v\", err)\n\t}\n\tfor _, modMap := range matcherSets.([]map[string]any) {\n\t\tvar ms MatcherSet\n\t\tfor _, modIface := range modMap {\n\t\t\tif mod, ok := modIface.(RequestMatcherWithError); ok {\n\t\t\t\tms = append(ms, mod)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif mod, ok := modIface.(RequestMatcher); ok {\n\t\t\t\tms = append(ms, mod)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"module is not a request matcher: %T\", modIface)\n\t\t}\n\t\tm.MatcherSets = append(m.MatcherSets, ms)\n\t}\n\treturn nil\n}","sourceCodeStart":1504,"sourceCodeEnd":1540,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/matchers.go#L1504-L1540","documentation":"MatchNot.Provision loads the raw nested matcher sets under a `not` directive via ctx.LoadModule. Any failure while instantiating a nested matcher (bad arguments, unknown module, its own provisioning error) is wrapped as \"loading matcher sets: %v\". The real cause is in the chained error text.","triggerScenarios":"`not` wrapping a matcher that itself fails provisioning, e.g. not path_regexp \"[bad\", not remote_ip 1.2.3.4/99, or a JSON `not` block referencing an unregistered custom matcher module.","commonSituations":"Complex negated matchers where the inner error is mistaken for a problem with `not`; third-party matcher plugins missing from the build; JSON configs with wrong field types inside `not`.","solutions":["Read the suffixed inner error — fix the nested matcher it describes, not the `not` itself.","Test the inner matcher standalone (without `not`) to reproduce the underlying error directly.","For missing plugins, rebuild Caddy with the plugin imported or remove the matcher."],"exampleFix":"// before (Caddyfile)\n@ok not path_regexp [bad\n\n// after\n@ok not path_regexp ^/private/.*","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// In Go, handle the wrapped chain and surface the inner cause\nif err := notMatcher.Provision(ctx); err != nil {\n\tinner := errors.Unwrap(err)\n\tif inner != nil {\n\t\tlog.Printf(\"not matcher failed because of nested matcher: %v\", inner)\n\t}\n\treturn err\n}","preventionTips":["Treat 'loading matcher sets:' as a wrapper — always read the suffixed cause.","Test the inner matcher without `not` to isolate failures.","Keep custom matcher plugins loaded in the binary."],"tags":["caddy","config","matcher","error-wrapping","not-matcher"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}