
React WebRTC: Cách Fix Lỗi Failed to set remote answer sdp
Mình đã mất khá nhiều thời gian để debug lỗi InvalidStateError: Failed to set remote answer sdp trong một ứng dụng React WebRTC sử dụng Simple-Peer và Socket.IO. Vấn đề thực sự không nằm ở SDP, mà đến từ duplicated signaling events, signaling state sai và cách React xử lý lifecycle. Đây là nguyên nhân thật sự và cách fix đã hoạt động với mình.
Nếu bạn đang build một ứng dụng video call bằng React và WebRTC rồi đột nhiên gặp lỗi:
InvalidStateError: Failed to set remote answer sdpthì bạn không phải người duy nhất đâu.
Mình đã mất khá nhiều thời gian để debug lỗi này khi xây dựng một ứng dụng video call sử dụng React, WebRTC, Simple-Peer và Socket.IO. Ban đầu mọi thứ trông hoàn toàn bình thường:
- signaling server hoạt động
- peer kết nối được
- ICE candidates được exchange đầy đủ
- SDP nhìn không có gì sai
Nhưng browser vẫn random quăng ra lỗi.
Điều khó chịu nhất là message này gần như không nói rõ nguyên nhân thật sự nằm ở đâu.
Trong trường hợp của mình, vấn đề thực tế liên quan đến WebRTC signaling state và việc xử lý SDP answer bị lặp.
Tại sao lỗi này xảy ra?
Lỗi này thường xuất hiện khi bạn cố gắng set một remote answer SDP trong lúc peer connection đang ở sai signaling state.
Nói đơn giản hơn:
WebRTC nhận được SDP answer vào thời điểm mà nó không mong đợi.
Điều này thường xảy ra khi:
- cùng một answer bị xử lý nhiều lần
- cả hai peer cùng tạo offer
- socket event bị duplicate
- React component re-render và tạo lại peer ngoài ý muốn
- signaling flow chạy sai thứ tự
Vấn đề thực tế của mình
Trong project của mình, mình vô tình xử lý socket event answer nhiều hơn một lần.
Kết quả:
- lần đầu
setRemoteDescription()chạy thành công - lần thứ hai cố apply lại cùng một SDP
- WebRTC reject ngay với lỗi:
Failed to set remote answer sdpLúc đầu mình nghĩ:
- ICE server có vấn đề
- STUN/TURN config bị sai
- SDP format không hợp lệ
Nhưng cuối cùng không phải mấy thứ đó.
Cách mình fix lỗi
Cách fix thực ra khá đơn giản:
- đảm bảo answer chỉ được xử lý một lần
- kiểm tra signaling state trước khi apply SDP
- tránh duplicate socket listeners
Implementation dễ gây lỗi
Đây là kiểu code rất dễ gây ra vấn đề:
socket.on("answer", (answer) => {
peer.signal(answer);
});Nhìn thì vô hại, nhưng nếu:
- listener bị register nhiều lần
- React re-render ngoài ý muốn
- cùng một event bị emit lại
thì peer.signal(answer) có thể chạy thêm lần nữa khi connection đã ở trạng thái stable.
Cách fix tốt hơn
Mình fix bằng cách kiểm tra signaling state trước khi signal:
socket.on("answer", (answer) => {
if (peer._pc.signalingState !== "stable") {
peer.signal(answer);
}
});Ngoài ra mình cũng cleanup socket listeners cẩn thận:
useEffect(() => {
socket.on("answer", handleAnswer);
return () => {
socket.off("answer", handleAnswer);
};
}, []);Sau khi làm vậy thì lỗi biến mất hoàn toàn.
Một nguyên nhân phổ biến khác trong React
React Strict Mode cũng có thể khiến lỗi này khó chịu hơn rất nhiều trong môi trường development.
Trong development mode, React có thể cố tình chạy effects hai lần.
Điều đó đồng nghĩa với việc:
- peer có thể bị tạo hai lần
- socket listeners bị duplicate
- SDP answer bị xử lý lặp
Nếu bạn chỉ gặp lỗi ở môi trường development nhưng production thì không, đây là dấu hiệu rất đáng nghi.
Những thứ nên kiểm tra
Nếu bạn vẫn đang bị mắc kẹt, hãy kiểm tra kỹ các thứ sau.
1. Tránh duplicate socket listeners
Không nên:
socket.on("answer", callback);ở những component re-render thường xuyên.
Nên:
- dùng
useEffect - cleanup listeners đầy đủ
- tránh register event lặp
2. Đừng tạo lại peer ngoài ý muốn
Một lỗi rất phổ biến:
const peer = new Peer();ngay trong render logic.
Hãy dùng:
useRef- stable initialization
- cleanup hợp lý
thay vào đó.
3. Tránh signal nhiều lần
Trước khi gọi:
peer.signal(data);hãy đảm bảo:
- peer vẫn còn tồn tại
- signaling state hợp lệ
- SDP chưa bị apply trước đó
4. Kiểm tra signaling flow
Thứ tự đúng thường là:
- tạo offer
- gửi offer
- tạo answer
- trả answer
- apply answer đúng một lần
Nếu events đến sai thứ tự, WebRTC sẽ rất dễ “nổi điên”.
Tip debug giúp mình tìm ra lỗi
Thứ giúp mình debug nhanh nhất là log signaling state trước khi apply SDP:
console.log(peer._pc.signalingState);Các state phổ biến:
stablehave-local-offerhave-remote-offer
Nếu bạn cố apply answer trong khi state đã là stable, browser rất dễ quăng lỗi này.
Kết luận
Con bug này khó chịu hơn mình nghĩ rất nhiều vì nguyên nhân thực sự không nằm ở SDP.
Vấn đề thật sự là:
- duplicated events
- signaling flow sai
- React lifecycle behavior
Nếu bạn đang dùng:
- React
- WebRTC
- Simple-Peer
- Socket.IO
thì khả năng rất cao lỗi của bạn cũng liên quan đến signaling state management.
Hy vọng bài viết này giúp bạn tiết kiệm được vài tiếng debug vô ích.
Thẻ
Bài viết liên quan

Cách dùng Google Maps hiệu quả hơn với các tính năng ít người biết
Phần lớn mọi người chỉ dùng Google Maps để tìm đường từ điểm A tới điểm B. Nhưng sau nhiều năm sử dụng gần như mỗi ngày, mình nhận ra ứng dụng này có rất nhiều tính năng nhỏ nhưng cực kỳ hữu ích mà đa số người dùng gần như bỏ qua. Từ việc lưu chỗ đậu xe, tải offline maps cho tới dùng Street View trước khi tới nơi lạ, đây là những Google Maps hacks đã âm thầm giúp mình tiết kiệm thời gian, đỡ stress hơn khi di chuyển và khiến trải nghiệm đi lại hằng ngày thoải mái hơn rất nhiều.

Những Google AI Pro hacks đã thay đổi workflow của mình
Dạo gần đây mình thấy khá nhiều người đã claim được gói student của Google AI Pro, nhưng đa số vẫn đang dùng nó giống như bản free — mở AI lên hỏi vài câu cơ bản, lâu lâu nhờ tóm tắt tài liệu hoặc viết lại vài đoạn văn. Trong khi sau một thời gian dùng thật cho việc viết content, research và học tập, mình thấy thứ đáng giá nhất của gói Pro lại không nằm ở chuyện “AI thông minh hơn”, mà là nó giúp workflow hằng ngày trở nên nhanh và liền mạch hơn rất nhiều.