{"record":{"id":"d1e12c784ad4dddb","repo":"router-for-me/CLIProxyAPI","slug":"codex-live-media-relay-udp-range-requires-at-least","errorCode":null,"errorMessage":"codex.live-media-relay UDP range requires at least %d ports for %d sessions","messagePattern":"codex\\.live-media-relay UDP range requires at least (.+?) ports for (.+?) sessions","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/codex_live.go","lineNumber":86,"sourceCode":"\t\treturn nil\n\t}\n\tif c.MaxSessions < 0 {\n\t\treturn errors.New(\"codex.live-media-relay.max-sessions must not be negative\")\n\t}\n\tif publicIP := strings.TrimSpace(c.PublicIP); publicIP != \"\" && net.ParseIP(publicIP) == nil {\n\t\treturn fmt.Errorf(\"codex.live-media-relay.public-ip is invalid: %q\", publicIP)\n\t}\n\tif (c.UDPPortMin == 0) != (c.UDPPortMax == 0) {\n\t\treturn errors.New(\"codex.live-media-relay UDP port minimum and maximum must both be set\")\n\t}\n\tif c.UDPPortMin > c.UDPPortMax {\n\t\treturn errors.New(\"codex.live-media-relay.udp-port-min must not exceed udp-port-max\")\n\t}\n\tif c.UDPPortMin != 0 {\n\t\tavailablePorts := int(c.UDPPortMax) - int(c.UDPPortMin) + 1\n\t\trequiredPorts := c.EffectiveMaxSessions() * 2\n\t\tif availablePorts < requiredPorts {\n\t\t\treturn fmt.Errorf(\"codex.live-media-relay UDP range requires at least %d ports for %d sessions\", requiredPorts, c.EffectiveMaxSessions())\n\t\t}\n\t}\n\tfor serverIndex, server := range c.ICEServers {\n\t\tif len(server.URLs) == 0 {\n\t\t\treturn fmt.Errorf(\"codex.live-media-relay.ice-servers[%d].urls is required\", serverIndex)\n\t\t}\n\t\tfor _, rawURL := range server.URLs {\n\t\t\tparsed, errParse := url.Parse(strings.TrimSpace(rawURL))\n\t\t\tif errParse != nil || parsed.Scheme == \"\" {\n\t\t\t\treturn fmt.Errorf(\"codex.live-media-relay.ice-servers[%d] contains an invalid URL\", serverIndex)\n\t\t\t}\n\t\t\tswitch strings.ToLower(parsed.Scheme) {\n\t\t\tcase \"stun\", \"stuns\", \"turn\", \"turns\":\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"codex.live-media-relay.ice-servers[%d] uses unsupported scheme %q\", serverIndex, parsed.Scheme)\n\t\t\t}\n\t\t}\n\t}","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/codex_live.go#L68-L104","documentation":"Each media session consumes 2 UDP ports in the configured range (one per side of the relayed flow), so Validate requires at least EffectiveMaxSessions()*2 ports between udp-port-min and udp-port-max. With the default 32 sessions that is 64 ports; a narrower range fails startup with this error.","triggerScenarios":"udp-port-min/udp-port-max are both non-zero, min<=max, but (max-min+1) < maxSessions*2 — e.g. min 50000, max 50020 (21 ports) with the default 32 sessions.","commonSituations":"Operators narrow the UDP range for firewall rules and forget the 2-ports-per-session requirement; raising max-sessions without widening the range.","solutions":["Widen the range to at least 2*maxSessions ports: for 32 sessions use >=64 ports (e.g. 50000-50099).","Or lower max-sessions so 2*sessions fits the current range.","Or leave both port bounds unset (0) to use the default unbounded behavior."],"exampleFix":"# before (21 ports < 64 needed for 32 sessions)\nudp-port-min: 50000\nudp-port-max: 50020\n\n# after\nudp-port-min: 50000\nudp-port-max: 50099","handlingStrategy":"validation","validationCode":"ports := cfg.UDPPortMax - cfg.UDPPortMin + 1\nif cfg.UDPPortMin != 0 && ports < cfg.EffectiveMaxSessions()*2 {\n\treturn fmt.Errorf(\"need >=%d UDP ports, have %d\", cfg.EffectiveMaxSessions()*2, ports)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Rule of thumb: allocate 2 ports per session plus headroom.","Whenever you change max-sessions, re-check the UDP range width."],"tags":["config","validation","udp","ports","codex-live","media-relay"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}