{"record":{"id":"e9d2101911117eca","repo":"caddyserver/caddy","slug":"marshaling-t-matcher-v-e9d210","errorCode":null,"errorMessage":"marshaling %T matcher: %v","messagePattern":"marshaling %T matcher: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/connpolicy.go","lineNumber":1125,"sourceCode":"\t\tdd := caddyfile.NewDispenser(tokens)\n\t\tdd.Next() // consume wrapper name\n\n\t\tunm, err := caddyfile.UnmarshalModule(dd, \"tls.handshake_match.\"+matcherName)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcm, ok := unm.(ConnectionMatcher)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"matcher module '%s' is not a connection matcher\", matcherName)\n\t\t}\n\t\tmatcherMap[matcherName] = cm\n\t}\n\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","sourceCodeStart":1107,"sourceCodeEnd":1132,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/connpolicy.go#L1107-L1132","documentation":"After a connection matcher is parsed from a Caddyfile, Caddy json.Marshal's it to store in the ModuleMap of the connection policy; if marshaling fails (unexported fields with no JSON tags, unsupported types like func or chan in the matcher struct), this error wraps the json error.","triggerScenarios":"Almost exclusively with third-party matcher modules whose structs contain unmarshalable fields; stock matchers marshal fine.","commonSituations":"Custom handshake matcher plugins during development; Go json rejecting types such as sync.Mutex, channels, or unexported complex fields.","solutions":["If this is your plugin, ensure all config fields are exported and JSON-marshalable; keep runtime-only state in separate unexported-but-ignored fields (add json:\"-\" where needed)","Rebuild the plugin against the deployed Caddy version","If stock Caddy hits this, report it — it indicates a regression in a built-in matcher"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Plugin authors: unit-test that matcher config marshals cleanly\nfunc TestMatcherMarshals(t *testing.T) {\n\tb, err := json.Marshal(&MyMatcher{ /* exported config fields */ })\n\tif err != nil {\n\t\tt.Fatalf(\"matcher not JSON-safe: %v\", err)\n\t}\n\tt.Log(string(b))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep matcher structs to exported, json-friendly fields; tag runtime state with json:\"-\"","Never embed funcs/channels/locks in config-carrying structs","Run go test on plugins in CI alongside caddy validate"],"tags":["tls","json","module-system","xcaddy"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}