{"record":{"id":"e6ecb43a882b8829","repo":"router-for-me/CLIProxyAPI","slug":"sdp-contains-inconsistent-bundled-ice-credentials","errorCode":null,"errorMessage":"SDP contains inconsistent bundled ICE credentials","messagePattern":"SDP contains inconsistent bundled ICE credentials","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"internal/client/codex/live/tcp_proxy.go","lineNumber":267,"sourceCode":"\t\tpassword := sessionPassword\n\t\tif mediaPassword, ok := media.Attribute(\"ice-pwd\"); ok {\n\t\t\tpassword = mediaPassword\n\t\t}\n\t\tufrag = strings.TrimSpace(ufrag)\n\t\tpassword = strings.TrimSpace(password)\n\t\tif ufrag == \"\" && password == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif ufrag == \"\" || password == \"\" {\n\t\t\treturn iceCredentials{}, errors.New(\"SDP contains incomplete ICE credentials\")\n\t\t}\n\t\tcurrent := iceCredentials{ufrag: ufrag, password: password}\n\t\tif selected.ufrag == \"\" {\n\t\t\tselected = current\n\t\t\tcontinue\n\t\t}\n\t\tif selected != current {\n\t\t\treturn iceCredentials{}, errors.New(\"SDP contains inconsistent bundled ICE credentials\")\n\t\t}\n\t}\n\tif selected.ufrag == \"\" {\n\t\tselected = iceCredentials{ufrag: strings.TrimSpace(sessionUfrag), password: strings.TrimSpace(sessionPassword)}\n\t}\n\tif selected.ufrag == \"\" || selected.password == \"\" {\n\t\treturn iceCredentials{}, errors.New(\"SDP is missing ICE credentials\")\n\t}\n\treturn selected, nil\n}\n\nfunc closeCandidateTunnels(tunnels []*tcpCandidateTunnel) error {\n\tvar closeErrors []error\n\tfor _, tunnel := range tunnels {\n\t\tif errClose := tunnel.Close(); errClose != nil {\n\t\t\tcloseErrors = append(closeErrors, errClose)\n\t\t}\n\t}","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/client/codex/live/tcp_proxy.go#L249-L285","documentation":"Thrown while extracting ICE credentials when two m= sections in the bundled upstream answer carry different ice-ufrag/ice-pwd pairs. The proxy rewrites candidates for the whole bundle using one credential set (remote ufrag ':' local ufrag), so inconsistent credentials across media sections cannot be handled and are rejected as a protocol violation (BUNDLE requires identical credentials).","triggerScenarios":"Upstream answer with multiple m= lines where at least one defines credentials differing from the others, while the TCP proxy dialer is enabled.","commonSituations":"Upstream server bug, non-BUNDLE-compliant SDP, or SDP mangling by an intermediary that rewrites one media section's credentials.","solutions":["Inspect the per-m-line a=ice-ufrag/a=ice-pwd values in the answer SDP and confirm they are identical","Report the non-BUNDLE-compliant answer to the upstream producer","Workaround: disable TCP proxying for the affected session"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Verify identical credentials across bundled m-lines before proxying\nseen := map[iceCredentials]bool{}\nfor _, m := range sdp.MediaDescriptions {\n    u, _ := m.Attribute(\"ice-ufrag\")\n    p, _ := m.Attribute(\"ice-pwd\")\n    if u != \"\" || p != \"\" {\n        seen[iceCredentials{u, p}] = true\n    }\n}\nif len(seen) > 1 {\n    return errors.New(\"non-BUNDLE-compliant answer; proxy will reject\")\n}","typeGuard":"func hasConsistentBundledCredentials(pairs []iceCredentials) bool {\n    first := \"\"\n    for _, c := range pairs {\n        if c.ufrag == \"\" { continue }\n        if first == \"\" { first = c.ufrag + \":\" + c.password; continue }\n        if c.ufrag+\":\"+c.password != first { return false }\n    }\n    return true\n}","tryCatchPattern":"if _, _, err := live.PrepareProxiedUpstreamAnswer(answer, offer, dialer); err != nil {\n    if strings.Contains(err.Error(), \"inconsistent bundled ICE credentials\") {\n        return fmt.Errorf(\"upstream violated BUNDLE credential rules; report to SDP producer: %w\", err)\n    }\n    return err\n}","preventionTips":["When generating multi-m-line SDP, reuse one ice-ufrag/ice-pwd pair for the bundle","Test SDP producers with multi-media-section offers"],"tags":["webrtc","sdp","ice","bundle","tcp-proxy"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}