{"record":{"id":"0ffeccce2bef96df","repo":"caddyserver/caddy","slug":"network-type-s-is-already-registered-0ffecc","errorCode":null,"errorMessage":"network type %s is already registered","messagePattern":"network type (.+?) is already registered","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"modules/caddyhttp/server.go","lineNumber":1506,"sourceCode":"var networkTypesHTTP3 = map[string]string{\n\t\"unixgram\": \"unixgram\",\n\t\"udp\":      \"udp\",\n\t\"udp4\":     \"udp4\",\n\t\"udp6\":     \"udp6\",\n\t\"tcp\":      \"udp\",\n\t\"tcp4\":     \"udp4\",\n\t\"tcp6\":     \"udp6\",\n\t\"fdgram\":   \"fdgram\",\n}\n\n// RegisterNetworkHTTP3 registers a mapping from non-HTTP/3 network to HTTP/3\n// network. This should be called during init() and will panic if the network\n// type is standard, reserved, or already registered.\n//\n// EXPERIMENTAL: Subject to change.\nfunc RegisterNetworkHTTP3(originalNetwork, h3Network string) {\n\tif _, ok := networkTypesHTTP3[strings.ToLower(originalNetwork)]; ok {\n\t\tpanic(\"network type \" + originalNetwork + \" is already registered\")\n\t}\n\tnetworkTypesHTTP3[originalNetwork] = h3Network\n}\n\nfunc getHTTP3Network(originalNetwork string) (string, error) {\n\th3Network, ok := networkTypesHTTP3[strings.ToLower(originalNetwork)]\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"network '%s' cannot handle HTTP/3 connections\", originalNetwork)\n\t}\n\treturn h3Network, nil\n}\n","sourceCodeStart":1488,"sourceCodeEnd":1518,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/server.go#L1488-L1518","documentation":"RegisterNetworkHTTP3 lets plugins map a custom listener network (registered via RegisterNetwork) to the network that its HTTP/3 (QUIC) listener should use. The mapping table is keyed by the original network name, lowercased; registering the same original network twice panics during init.","triggerScenarios":"Two plugins both calling caddyhttp.RegisterNetworkHTTP3(\"myplugin:net\", \"udp\") for the same original network, or one plugin registering it in two init paths.","commonSituations":"Fork/duplicate plugin linking (same as other duplicate-registration panics); a plugin bundle where two modules assume responsibility for the same custom network's HTTP/3 mapping.","solutions":["Ensure exactly one plugin owns the HTTP/3 mapping for a given network name","Inspect linked plugins (caddy list-modules --packages) and de-duplicate imports/go.mod replaces","Call RegisterNetworkHTTP3 only in the same init() that registers the network"],"exampleFix":"// before\n// plugin A: caddyhttp.RegisterNetworkHTTP3(\"tunnel\", \"udp\")\n// plugin B: caddyhttp.RegisterNetworkHTTP3(\"tunnel\", \"udp\") // panic\n// after\n// only plugin A registers it; plugin B omits the call","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["One HTTP/3 registration per network name across the binary","Call RegisterNetworkHTTP3 next to RegisterNetwork in the same init()","De-duplicate linked plugins via go.mod replace"],"tags":["caddy","go","http3","network","plugin","duplicate-registration","panic"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}