
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

Vì sao design và engineering vẫn luôn lệch khỏi nhau trong các product team hiện đại
Các product team hiện đại vẫn luôn gặp khó khăn với khoảng cách giữa design intent và sản phẩm thực tế được ship. Bài viết phân tích vì sao designer và engineer thường nhìn sản phẩm theo những cách khác nhau, cách handoff culture tạo ra sự lệch pha, và tại sao design engineering có thể là chìa khóa để xây dựng trải nghiệm số đồng nhất hơn.

Cách Designer Collaboration Tốt Hơn Với Engineer
Những sản phẩm tốt hiếm khi được tạo ra chỉ bởi design hoặc engineering riêng lẻ. Bài viết này chia sẻ những cách thực tế giúp designer làm việc hiệu quả hơn với engineer, từ việc hiểu technical constraint, giao tiếp bằng cùng “ngôn ngữ” cho tới cải thiện QA và product workflow.

Vì sao những product team tốt nhất đang dần từ bỏ design handoff
Design handoff truyền thống thường tạo ra khoảng cách giữa designer và developer, dẫn tới workflow chậm chạp, implementation issue và sản phẩm dần lệch khỏi design intent ban đầu. Bài viết này phân tích vì sao nhiều product team hiện đại đang thay thế handoff culture bằng collaboration liên tục, shared prototype và workflow gắn kết hơn giữa design và engineering.