{"record":{"id":"73ad6c42d1a5c505","repo":"caddyserver/caddy","slug":"starting-http-3-quic-listener-v","errorCode":null,"errorMessage":"starting HTTP/3 QUIC listener: %v","messagePattern":"starting HTTP/3 QUIC listener: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"modules/caddyhttp/server.go","lineNumber":942,"sourceCode":"\t}\n\n\t// If we didn't actually find a host matcher, return 0\n\t// because that means every defined route was a \"catch-all\".\n\t// See https://caddy.community/t/how-to-set-priority-in-caddyfile/13002/8\n\tif !foundHostMatcher {\n\t\treturn 0\n\t}\n\n\treturn lastIndex\n}\n\n// serveHTTP3 creates a QUIC listener, configures an HTTP/3 server if\n// not already done, and then uses that server to serve HTTP/3 over\n// the listener, with Server s as the handler.\nfunc (s *Server) serveHTTP3(addr caddy.NetworkAddress, tlsCfg *tls.Config) error {\n\th3net, err := getHTTP3Network(addr.Network)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"starting HTTP/3 QUIC listener: %v\", err)\n\t}\n\taddr.Network = h3net\n\th3ln, err := addr.ListenQUIC(s.ctx, 0, net.ListenConfig{}, tlsCfg, s.packetConnWrappers, s.Allow0RTT)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"starting HTTP/3 QUIC listener: %v\", err)\n\t}\n\n\t// create HTTP/3 server if not done already\n\tif s.h3server == nil {\n\t\ts.h3server = &http3.Server{\n\t\t\tHandler:        s,\n\t\t\tTLSConfig:      tlsCfg,\n\t\t\tMaxHeaderBytes: s.MaxHeaderBytes,\n\t\t\tQUICConfig: &quic.Config{\n\t\t\t\tVersions:          []quic.Version{quic.Version1, quic.Version2},\n\t\t\t\tInitialPacketSize: 1200,\n\t\t\t\tTracer:            h3qlog.DefaultConnectionTracer,\n\t\t\t},","sourceCodeStart":924,"sourceCodeEnd":960,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/server.go#L924-L960","documentation":"serveHTTP3 resolves the QUIC-equivalent network for the listener's network string via getHTTP3Network before opening the QUIC listener; this wrapper fires when that mapping is missing — i.e. the configured network type has no HTTP/3 counterpart registered. The wrapped error is \"network '%s' cannot handle HTTP/3 connections\".","triggerScenarios":"A server with HTTP/3 enabled whose listen address uses a network not registered for HTTP/3 (see RegisterNetworkHTTP3), e.g. a custom/Unix network string while protocols includes h3.","commonSituations":"Custom builds registering exotic network types (transparent sockets, Unix datagram) without also calling caddyhttp.RegisterNetworkHTTP3; enabling h3 on a server bound to a nonstandard network.","solutions":["Use a standard network (tcp/tcp4/tcp6) for listeners that serve HTTP/3","If you maintain the custom network type, call caddyhttp.RegisterNetworkHTTP3(original, h3net) with a UDP-based equivalent in an init() before serving","Disable HTTP/3 (remove h3 from server protocols) for listeners on networks without QUIC support"],"exampleFix":"// before (custom network, no h3 mapping)\ncaddy.ListenPacket on \"mysock\" network with protocols [\"h1\",\"h2\",\"h3\"]\n\n// after\nfunc init() {\n  caddyhttp.RegisterNetworkHTTP3(\"mysock\", \"mysock_udp\")\n}","handlingStrategy":"validation","validationCode":"// before enabling h3 on a custom network:\nregistered := map[string]bool{\"tcp\": true, \"tcp4\": true, \"tcp6\": true} // + custom RegisterNetworkHTTP3 entries\nif !registered[strings.ToLower(addr.Network)] && slices.Contains(s.Protocols, \"h3\") {\n    return fmt.Errorf(\"network %q cannot serve h3; register an HTTP/3 mapping or drop h3\", addr.Network)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Plugin authors: always pair custom network registration with RegisterNetworkHTTP3","Keep h3 listeners on standard tcp networks"],"tags":["caddy","http3","quic","network","listeners","startup"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}