A 400 Bad Request may occur when multiple simultaneous WebRTC connections are made.

We display IP camera video obtained via the WebRTC REST API on video panels on a dashboard.

There is no issue when the dashboard has a single video panel, but when attempting to display simultaneously on two or more video panels,

XProtect returns a 400 Bad Request RESPONSE to the REQUEST (POST /api/xprotect/v1.0/session), and the video display may fail.

We will provide the following information; please identify the cause and propose countermeasures:

- Environment information

- REQUEST and RESPONSE details for both successful and failed cases

- Excerpts of the relevant portions of the XProtect API Gateway DEBUG log

■Environment information

Using WebRTC in XProtect Professional+ 2024 R2

camera01 Id: f131f2e3-fd8d-457a-8d6d-858418301b1d

camera02 Id: c278841f-d97e-4311-a59b-a04ef8d469e1

■Successful REQUEST

POST /api/xprotect/v1.0/session HTTP/1.1

Accept: */*

Accept-Encoding: gzip, deflate, br, zstd

Accept-Language: ja,en;q=0.9,en-GB;q=0.8,en-US;q=0.7

Cache-Control: no-cache

Connection: keep-alive

Content-Length: 252

Content-Type: application/json

Cookie: i18next=ja; timeLineRange=%7B%22from%22%3Anull%2C%22to%22%3Anull%2C%22select%22%3A%22live%22%7D

Host: 192.168.1.155:8443

Origin: https://192.168.1.155:8443

Pragma: no-cache

Referer: https://192.168.1.155:8443/panel_groups?id=2e0be14c-0de1-4506-a3de-30890013ea1a

Sec-Fetch-Dest: empty

Sec-Fetch-Mode: cors

Sec-Fetch-Site: same-origin

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0

sec-ch-ua: “Microsoft Edge”;v=“141”, “Not?A_Brand”;v=“8”, “Chromium”;v=“141”

sec-ch-ua-mobile: ?0

sec-ch-ua-platform: “Windows”

{

“deviceId”: “c278841f-d97e-4311-a59b-a04ef8d469e1”,

“cameraId”: “c278841f-d97e-4311-a59b-a04ef8d469e1”,

“playbackTimeNode”: {

"playbackTime": "2025-12-06T15:00:00.000Z",

"skipGaps": false,

"speed": 1

},

“iceServers”: [],

“resolution”: “notInUse”,

“includeAudio”: false

}

※Note: To support both XProtext 2024 R2 and 2025 R2, we are POSTing both deviceId and cameraId.

■Successful RESPONSE

HTTP/1.1 200 OK

Server: nginx/1.27.1

Date: Sun, 07 Dec 2025 23:35:19 GMT

Content-Type: application/json

Content-Length: 1810

Connection: keep-alive

access-control-allow-origin: https://192.168.1.155:8443

access-control-allow-credentials: true

vary: Origin

{“sessionId”:“1b85f631-6496-4066-944b-6c5873f4abb9”,“offerSDP”:“{\“type\”:\“offer\”,\“sdp\”:\“v=0[\\r\\no=-](file://r//no=-) 98502 0 IN IP4 127.0.0.1[\\r\\ns=sipsorcery\\r\\nt=0](file://r//ns=sipsorcery//r//nt=0) 0[\\r\\na=group](file://r//na=group):BUNDLE 0 1[\\r\\nm=video](file://r//nm=video) 9 UDP/TLS/RTP/SAVP 101 102 103[\\r\\nc=IN](file://r//nc=IN) IP4 0.0.0.0[\\r\\na=ice-ufrag](file://r//na=ice-ufrag):KFVJ[\\r\\na=ice-pwd](file://r//na=ice-pwd):QAEAGKYMDZLYIQIERAOODEIX[\\r\\na=fingerprint](file://r//na=fingerprint):sha-256 EA:EC:5F:D5:54:A9:BA:A5:CA:75:C5:F1:C0:E4:E6:BB:30:5E:F7:2A:F6:F4:99:51:07:57:3E:7B:82:5B:8A:66[\\r\\na=setup](file://r//na=setup):actpass[\\r\\na=candidate](file://r//na=candidate):1266949509 1 udp 2113937663 192.168.1.154 64242 typ host generation 0[\\r\\na=ice-options](file://r//na=ice-options):ice2,trickle[\\r\\na=mid](file://r//na=mid):0[\\r\\na=rtpmap](file://r//na=rtpmap):101 H264/90000[\\r\\na=rtcp-fb](file://r//na=rtcp-fb):101 goog-remb[\\r\\na=fmtp](file://r//na=fmtp):101 packetization-mode=1;level-asymmetry-allowed=1;profile-level-id=42e01f[\\r\\na=rtpmap](file://r//na=rtpmap):102 H264/90000[\\r\\na=rtcp-fb](file://r//na=rtcp-fb):102 goog-remb[\\r\\na=fmtp](file://r//na=fmtp):102 packetization-mode=1;level-asymmetry-allowed=1;profile-level-id=42e034[\\r\\na=rtpmap](file://r//na=rtpmap):103 H264/90000[\\r\\na=rtcp-fb](file://r//na=rtcp-fb):103 goog-remb[\\r\\na=fmtp](file://r//na=fmtp):103 profile-level-id=42e01f[\\r\\na=extmap](file://r//na=extmap):2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\na=rtcp-mux\\r\\na=rtcp:9 IN IP4 0.0.0.0[\\r\\na=end-of-candidates\\r\\na=sendonly\\r\\na=ssrc](file://r//na=end-of-candidates//r//na=sendonly//r//na=ssrc):1998986647 cname:f70e8f7b-5e18-495a-bfde-8c25fa98cfb6[\\r\\nm=application](file://r//nm=application) 9 UDP/DTLS/SCTP webrtc-datachannel[\\r\\nc=IN](file://r//nc=IN) IP4 0.0.0.0[\\r\\na=ice-ufrag](file://r//na=ice-ufrag):KFVJ[\\r\\na=ice-pwd](file://r//na=ice-pwd):QAEAGKYMDZLYIQIERAOODEIX[\\r\\na=fingerprint](file://r//na=fingerprint):sha-256 EA:EC:5F:D5:54:A9:BA:A5:CA:75:C5:F1:C0:E4:E6:BB:30:5E:F7:2A:F6:F4:99:51:07:57:3E:7B:82:5B:8A:66[\\r\\na=setup](file://r//na=setup):actpass[\\r\\na=ice-options](file://r//na=ice-options):ice2,trickle[\\r\\na=mid](file://r//na=mid):1[\\r\\na=extmap](file://r//na=extmap):2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\na=sctp-port:5000\\r\\na=max-message-size:262144\\r\\n\”}”,“answerSDP”:“Uninitialised”,“playbackTimeNode”:{“playbackTime”:“2025-12-07T23:35:27.119Z”,“skipGaps”:false,“speed”:1.0},“includeAudio”:false}

■Failed REQUEST

POST /api/xprotect/v1.0/session HTTP/1.1

Accept: */*

Accept-Encoding: gzip, deflate, br, zstd

Accept-Language: ja,en;q=0.9,en-GB;q=0.8,en-US;q=0.7

Cache-Control: no-cache

Connection: keep-alive

Content-Length: 252

Content-Type: application/json

Cookie: i18next=ja; timeLineRange=%7B%22from%22%3Anull%2C%22to%22%3Anull%2C%22select%22%3A%22live%22%7D

Host: 192.168.1.155:8443

Origin: https://192.168.1.155:8443

Pragma: no-cache

Referer: https://192.168.1.155:8443/panel_groups?id=2e0be14c-0de1-4506-a3de-30890013ea1a

Sec-Fetch-Dest: empty

Sec-Fetch-Mode: cors

Sec-Fetch-Site: same-origin

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0

sec-ch-ua: “Microsoft Edge”;v=“141”, “Not?A_Brand”;v=“8”, “Chromium”;v=“141”

sec-ch-ua-mobile: ?0

sec-ch-ua-platform: “Windows”

{

“deviceId”: “f131f2e3-fd8d-457a-8d6d-858418301b1d”,

“cameraId”: “f131f2e3-fd8d-457a-8d6d-858418301b1d”,

“playbackTimeNode”: {

"playbackTime": "2025-12-06T15:00:00.000Z",

"skipGaps": false,

"speed": 1

},

“iceServers”: [],

“resolution”: “notInUse”,

“includeAudio”: false

}

■Failed RESPONSE

HTTP/1.1 400 Bad Request

Server: nginx/1.27.1

Date: Sun, 07 Dec 2025 23:35:19 GMT

Content-Type: application/json

Content-Length: 42

Connection: keep-alive

access-control-allow-origin: https://192.168.1.155:8443

access-control-allow-credentials: true

vary: Origin

{“error”:“Request failed with status 400”}

■Excerpts of the relevant portions of the XProtect API Gateway DEBUG log

I have attached gateway-0002.log.

The relevant section is from 2025-12-08 15:14:14.779+09:00 to 2025-12-08 15:14:40.888+09:00.

posted a file.

I tried to reproduce. I found that the WebRTC - JavaScript client sample is not suitable, does not have the capability to use more than one camera and connection, and is not easily changed to use multiple cameras and connections.

Do you have a minimal implementation small test app that you could share with us? If we had that from you we could reproduce and it would greatly increase the chance of us resolving this quickly.

PS. If you want to share minimal implementation test app source code with Milestone Support but not in the public website here, let me know, I can arrange a special upload area for this.

Thank you for your response.

We considered providing a small test app with a minimal implementation, but that would be difficult.

As a first step, could you check whether the issue can be reproduced by simultaneously starting the WebRTC JavaScript from multiple browsers, each specifying a different camera?

Please consider this.

Please add the following collaborators to this case:

Reason:
I inquired via chat whether it would be possible to configure case notifications to be sent to people other than the original inquirer.
I was advised that this could be arranged by mentioning the request in the case comments or case description for each case.
Note:
Both individuals already have Milestone accounts.

I cannot do this as an admin. Please advise the two:

  1. Login on the forum

  2. Open the topic (you can share the link to them)

  3. Scroll to the bottom (right side of the timeline)

  4. Click the :bell: bell icon

  5. Choose Watching or Tracking