{"record":{"id":"0f41253b3da4ef28","repo":"router-for-me/CLIProxyAPI","slug":"codex-live-media-relay-udp-port-min-must-not-excee","errorCode":null,"errorMessage":"codex.live-media-relay.udp-port-min must not exceed udp-port-max","messagePattern":"codex\\.live-media-relay\\.udp-port-min must not exceed udp-port-max","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/codex_live.go","lineNumber":80,"sourceCode":"\treturn DefaultCodexLiveMediaMaxSessions\n}\n\n// Validate verifies the Codex Live media relay configuration.\nfunc (c CodexLiveMediaRelayConfig) Validate() error {\n\tif !c.Enabled {\n\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) {","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/codex_live.go#L62-L98","documentation":"Validation error for codex.live-media-relay: udp-port-min is greater than udp-port-max. An inverted range cannot reserve ports for sessions, so Validate() rejects it. Note the follow-on check: when the range is valid it must also contain at least 2 ports per configured session.","triggerScenarios":"Config with enabled: true where udp-port-min > udp-port-max (e.g. 50100 / 50000).","commonSituations":"Swapped values when hand-editing config; copy-paste from examples with different orderings.","solutions":["Swap the values so udp-port-min <= udp-port-max","Confirm the corrected range spans at least 2 * EffectiveMaxSessions() ports","Confirm the ports are actually free/open on the host firewall"],"exampleFix":"# before\ncodex:\n  live-media-relay:\n    enabled: true\n    udp-port-min: 50100\n    udp-port-max: 50000\n# after\ncodex:\n  live-media-relay:\n    enabled: true\n    udp-port-min: 50000\n    udp-port-max: 50100","handlingStrategy":"validation","validationCode":"r := cfg.Codex.LiveMediaRelay\nif r.Enabled && r.UDPPortMin != 0 && r.UDPPortMin > r.UDPPortMax {\n    return fmt.Errorf(\"udp range inverted: min=%d max=%d\", r.UDPPortMin, r.UDPPortMax)\n}","typeGuard":null,"tryCatchPattern":"if err := relayCfg.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"must not exceed udp-port-max\") {\n        return errors.New(\"config fix: swap udp-port-min/udp-port-max so min <= max\")\n    }\n    return err\n}","preventionTips":["Double-check range ordering after any manual config edit","Reserve at least 2 * max-sessions ports in the range and open them in the firewall"],"tags":["config","validation","codex","media-relay","udp"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}