{"record":{"id":"e2bda40a29639f10","repo":"router-for-me/CLIProxyAPI","slug":"codex-live-media-relay-ice-servers-d-contains-an","errorCode":null,"errorMessage":"codex.live-media-relay.ice-servers[%d] contains an invalid URL","messagePattern":"codex\\.live-media-relay\\.ice-servers\\[(.+?)\\] contains an invalid URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/codex_live.go","lineNumber":96,"sourceCode":"\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}\n\treturn nil\n}\n","sourceCodeStart":78,"sourceCodeEnd":107,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/config/codex_live.go#L78-L107","documentation":"Each ICE server URL must parse with net/url and carry a scheme. This error fires when url.Parse fails or the scheme is empty — the URL is structurally broken (control characters, missing scheme separator, or just a bare host).","triggerScenarios":"Validate iterates server.URLs; a raw URL like 'turn.example.com:3478' (no turn: scheme), 'stun://stun host' (space), or one containing characters net/url rejects.","commonSituations":"Omitting the scheme and writing host:port only; copy-paste adding a space or smart quote; using ':3478' style after scheme incorrectly.","solutions":["Write full URLs with scheme: 'stun:stun.l.google.com:19302', 'turn:host:3478?transport=udp', 'turns:host:5349?transport=tcp'.","Trim stray whitespace/quotes around each URL in the config.","Validate each URL with url.Parse in a pre-deploy lint if configs are generated."],"exampleFix":"# before\nurls:\n  - turn.example.com:3478\n\n# after\nurls:\n  - turn:turn.example.com:3478?transport=tcp","handlingStrategy":"validation","validationCode":"for _, u := range server.URLs {\n\tp, err := url.Parse(strings.TrimSpace(u))\n\tif err != nil || p.Scheme == \"\" {\n\t\treturn fmt.Errorf(\"invalid ICE server URL %q\", u)\n\t}\n}","typeGuard":"func isValidICEServerURL(raw string) bool {\n\tp, err := url.Parse(strings.TrimSpace(raw))\n\treturn err == nil && p.Scheme != \"\"\n}","tryCatchPattern":null,"preventionTips":["Always include the scheme: 'stun:host:port', not 'host:port'.","Quote URLs containing '?' in YAML to avoid parser surprises."],"tags":["config","validation","ice-servers","url","codex-live"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}