{"record":{"id":"da5fba859018e7c6","repo":"AlexxIT/go2rtc","slug":"wrong-candidate-address","errorCode":null,"errorMessage":"wrong candidate: ${address}","messagePattern":"wrong candidate: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/webrtc/helpers.go","lineNumber":134,"sourceCode":"\t\tif pcma != nil && pcm == nil {\n\t\t\tpcm = pcma.Clone()\n\t\t\tpcm.Name = core.CodecPCM\n\t\t\tmedia.Codecs = append(media.Codecs, pcm)\n\t\t}\n\t\tif pcma != nil && pcml == nil {\n\t\t\tpcml = pcma.Clone()\n\t\t\tpcml.Name = core.CodecPCML\n\t\t\tmedia.Codecs = append(media.Codecs, pcml)\n\t\t}\n\t}\n\n\treturn medias\n}\n\nfunc NewCandidate(network, address string) (string, error) {\n\ti := strings.LastIndexByte(address, ':')\n\tif i < 0 {\n\t\treturn \"\", errors.New(\"wrong candidate: \" + address)\n\t}\n\thost, port := address[:i], address[i+1:]\n\n\ti, err := strconv.Atoi(port)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tconfig := &ice.CandidateHostConfig{\n\t\tNetwork:   network,\n\t\tAddress:   host,\n\t\tPort:      i,\n\t\tComponent: ice.ComponentRTP,\n\t}\n\n\tif network == \"tcp\" {\n\t\tconfig.TCPType = ice.TCPTypePassive\n\t}","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/webrtc/helpers.go#L116-L152","documentation":"pkg/webrtc NewCandidate builds an SDP candidate string from a network type and an address. It requires 'host:port' form — it splits at the last colon to separate host and port. If the address has no colon, there is no port and the function refuses to build a malformed candidate.","triggerScenarios":"Calling webrtc NewCandidate with an address string lacking a port, e.g. '192.168.1.5' or 'example.com', instead of '192.168.1.5:50000'.","commonSituations":"Passing an IP or hostname from config that never had the port appended; parsing candidates from a log and dropping the port portion; using an address string that got truncated (empty string also has no colon).","solutions":["Pass the address in host:port form, e.g. NewCandidate(\"udp4\", \"192.168.1.5:50000\")","Append the listening/default port programmatically when the source address has none","Validate the address contains a ':' and the port is numeric before calling"],"exampleFix":"// before\ncandidate, err := webrtc.NewCandidate(\"udp4\", \"192.168.1.5\")\n// after\ncandidate, err := webrtc.NewCandidate(\"udp4\", \"192.168.1.5:50000\")","handlingStrategy":"validation","validationCode":"if !strings.Contains(address, \":\") {\n    return fmt.Errorf(\"candidate address must be host:port, got %q\", address)\n}\nport, err := strconv.Atoi(address[strings.LastIndexByte(address, ':')+1:])\nif err != nil || port <= 0 || port > 65535 { /* reject */ }","typeGuard":"func hasHostPort(addr string) bool {\n    i := strings.LastIndexByte(addr, ':')\n    if i < 0 { return false }\n    p, err := strconv.Atoi(addr[i+1:])\n    return err == nil && p > 0 && p <= 65535\n}","tryCatchPattern":null,"preventionTips":["Always join host and port explicitly with net.JoinHostPort","Never hand-truncate addresses parsed from logs or SDP"],"tags":["webrtc","sdp","candidate","address-format"],"backgroundTag":"invalid-url-format","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}