Getting Failed to send message to peer: TimeoutError: signal timed out when sending a message from b2b relayed peers
-
Version: libp2p: "^2.8.3"
-
Platform: Windows 11 64-bit
-
Subsystem: @libp2p/circuit-relay-v2: "^3.2.9" react: "^18.3.1" Browser: Edge v 135.0.3179.98
Severity:
High
Description:
- What you did
- I created two browser clients on different windows machine each one is connected to different networks. Also, I have a relay that is working on a machine with a private static IP. I tried to send a message from one client to another through the relay, I got a message that the two peers connected each peer sees the other, but the message that is sent from one peer doesn't seem to be deliver to the second peer and the peer that sends the message return the following error:
Failed to send message to peer: TimeoutError: signal timed out
Steps to reproduce the error:
The config of the relay
const options = {
privateKey: privateKey,
addresses: {
listen: ["/ip4/0.0.0.0/tcp/9001/ws", "/ip4/0.0.0.0/tcp/9002"],
// announce: [
// "/dns4/relay-node.bfhkdgcdc9bxfebs.westus2.azurecontainer.io/tcp/9001/ws",
// ],
},
transports: [webSockets(), tcp()],
connectionEncrypters: [noise()],
streamMuxers: [yamux()],
connectionGater: {
// Allow private addresses for local testing
denyDialMultiaddr: () => false,
},
services: {
identify: identify(),
autoNat: autoNAT(),
relay: circuitRelayServer(),
ping: ping(),
},
// datastore,
};
The config of the client
const options: Libp2pOptions = {
privateKey: privateKey,
addresses: {
listen: ["/ip4/0.0.0.0/tcp/9001", "/p2p-circuit", "/webrtc"],
},
transports: [
webSockets(),
webTransport(),
webRTC(),
circuitRelayTransport(),
],
peerDiscovery: [
bootstrap({
list: [
"/ip4/RELAY_PUBLIC_IP/tcp/9001/ws/p2p/12D3KooWF6ttBYsoHXQs9FbCUeafdJabVQpYJYPcuHkMrRv9zoFY"
],
}),
],
connectionEncrypters: [noise()],
streamMuxers: [yamux()],
connectionGater: {
// Allow private addresses for local testing
denyDialMultiaddr: () => false,
},
connectionManager: {
inboundStreamProtocolNegotiationTimeout: 1e4,
inboundUpgradeTimeout: 1e4,
outboundStreamProtocolNegotiationTimeout: 1e4,
outboundUpgradeTimeout: 1e4,
},
services: {
identify: identify(),
ping: ping(),
dcutr: dcutr()
// keychain: keychain(keychainInit),
},
// datastore,
};
The package.json file in client
"dependencies": {
"@chainsafe/libp2p-noise": "latest",
"@chainsafe/libp2p-yamux": "latest",
"@libp2p/bootstrap": "^11.0.33",
"@libp2p/circuit-relay-v2": "^3.2.9",
"@libp2p/dcutr": "^2.0.29",
"@libp2p/echo": "^2.1.19",
"@libp2p/identify": "latest",
"@libp2p/interface": "^2.8.0",
"@libp2p/interface-peer-id": "^2.0.2",
"@libp2p/kad-dht": "^15.0.0",
"@libp2p/keychain": "^5.2.0",
"@libp2p/mdns": "latest",
"@libp2p/peer-id-factory": "^4.2.4",
"@libp2p/ping": "^2.0.29",
"@libp2p/tcp": "latest",
"@libp2p/webrtc": "^5.2.10",
"@libp2p/webrtc-star": "^7.0.0",
"@libp2p/websockets": "^9.2.9",
"@libp2p/webtransport": "^5.0.38",
"@multiformats/multiaddr": "^12.3.4",
"axios": "^1.8.4",
"browser-readline": "^0.0.1-security",
"browserify-fs": "^1.0.0",
"buffer": "^6.0.3",
"clsx": "^2.1.0",
"crypto-browserify": "^3.12.1",
"datastore-core": "^10.0.2",
"datastore-idb": "^3.0.1",
"dexie": "^4.0.11",
"idb": "^8.0.2",
"it-length-prefixed": "^9.1.0",
"it-map": "^3.1.1",
"it-pipe": "^3.0.1",
"libp2p": "^2.8.3",
"libp2p-gossipsub": "^0.13.0",
"lucide-react": "^0.344.0",
"p-defer": "^4.0.1",
"qrcode.react": "^4.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"stream-browserify": "^3.0.0",
"tailwind-merge": "^2.2.1",
"uint8arrays": "^5.1.0",
"util": "^0.12.5",
"wrtc": "^0.4.7"
},
The package.json file in relay
"dependencies": {
"@chainsafe/libp2p-gossipsub": "^14.1.1",
"@chainsafe/libp2p-noise": "latest",
"@chainsafe/libp2p-yamux": "latest",
"@libp2p/autonat": "^2.0.29",
"@libp2p/circuit-relay-v2": "^3.2.9",
"@libp2p/identify": "latest",
"@libp2p/keychain": "^5.2.0",
"@libp2p/ping": "^2.0.29",
"@libp2p/tcp": "latest",
"@libp2p/websockets": "^9.2.9",
"datastore-idb": "^3.0.1",
"datastore-level": "^11.0.1",
"level": "^9.0.0",
"libp2p": "^2.8.3",
"cross-env": "^7.0.3"
},
The log of the relay when the first client connects to it using bootstrap:
libp2p:websockets:listener new inbound connection /ip4/CLIENT_1_IP/tcp/12791 +0ms
libp2p:websockets:maconn encrypting inbound connection to /ip4/CLIENT_1_IP/tcp/12791 using /noise +0ms
libp2p:websockets:maconn successfully upgraded inbound connection +89ms
Connected to peer: 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU
libp2p:connection-manager:connection-pruner checking max connections limit 1/300 +0ms
libp2p:connection:inbound:bfpqq71745825622167 incoming stream opened on /ipfs/id/1.0.0 +0ms
libp2p:identify identify completed for peer 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU and protocols [ '/chat/1.0.0', '/ipfs/id/1.0.0', '/ipfs/ping/1.0.0', '/libp2p/circuit/relay/0.2.0/stop', '/libp2p/dcutr', '/webrtc-signaling/0.0.1' ] +0ms
libp2p:identify received identify from 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +3ms
libp2p:identify 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU did not send a signed peer record +1ms
libp2p:connection:inbound:bfpqq71745825622167 incoming stream opened on /libp2p/circuit/relay/0.2.0/hop +182ms
libp2p:circuit-relay:server received circuit v2 hop protocol stream from 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +0ms
libp2p:circuit-relay:server received RESERVE +46ms
libp2p:circuit-relay:server received hop message +7ms
libp2p:circuit-relay:server hop reserve request from 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +0ms
libp2p:circuit-relay:server:reservation-store creating new reservation for client 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +0ms
libp2p:circuit-relay:server sent confirmation response to 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +11ms
The log of the relay when the second client connects to it using boostrap:
libp2p:websockets:listener new inbound connection /ip4/CLIENT_2_IP/tcp/51766 +1m
libp2p:websockets:maconn encrypting inbound connection to /ip4/CLIENT_2_IP/tcp/51766 using /noise +0ms
libp2p:websockets:maconn successfully upgraded inbound connection +554ms
Connected to peer: 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS
libp2p:connection-manager:connection-pruner checking max connections limit 2/300 +1m
libp2p:connection:inbound:c16h4d1745825699119 incoming stream opened on /ipfs/id/1.0.0 +0ms
libp2p:identify identify completed for peer 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS and protocols [ '/chat/1.0.0', '/ipfs/id/1.0.0', '/ipfs/ping/1.0.0', '/libp2p/circuit/relay/0.2.0/stop', '/libp2p/dcutr', '/webrtc-signaling/0.0.1' ] +1m
libp2p:identify received identify from 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS +1ms
libp2p:identify 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS did not send a signed peer record +0ms
libp2p:connection:inbound:c16h4d1745825699119 incoming stream opened on /libp2p/circuit/relay/0.2.0/hop +210ms
libp2p:circuit-relay:server received circuit v2 hop protocol stream from 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS +1m
libp2p:circuit-relay:server received RESERVE +52ms
libp2p:circuit-relay:server received hop message +1ms
libp2p:circuit-relay:server hop reserve request from 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS +12ms
libp2p:circuit-relay:server:reservation-store creating new reservation for client 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS +1m
libp2p:circuit-relay:server sent confirmation response to 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS +7ms
The log of the relay when the CLIENT_2 sends a message to CLIENT_1
libp2p:connection:inbound:3n4u841745825835789 incoming stream opened on /ipfs/id/1.0.0 +0ms
libp2p:connection:inbound:3n4u841745825835789 incoming stream opened on /libp2p/circuit/relay/0.2.0/hop +58ms
libp2p:circuit-relay:server received circuit v2 hop protocol stream from 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS +13s
libp2p:identify identify completed for peer 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS and protocols [ '/chat/1.0.0', '/ipfs/id/1.0.0', '/ipfs/ping/1.0.0', '/libp2p/circuit/relay/0.2.0/stop', '/libp2p/dcutr', '/webrtc-signaling/0.0.1' ] +13s
libp2p:identify received identify from 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS +1ms
libp2p:circuit-relay:server received CONNECT +16ms
libp2p:circuit-relay:server received hop message +0ms
libp2p:circuit-relay:server hop connect request from 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS +1ms
libp2p:circuit-relay:server starting circuit relay v2 stop request to 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +0ms
libp2p:circuit-relay:server stop request to 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU was successful +22ms
libp2p:circuit-relay:server connection from 12D3KooWKwewVcnTea4asuLFHVgDaKAPpGvPx9R3fgEu5tWqdsYS to 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU established - merging streams +1ms
libp2p:circuit-relay:server limiting relayed connection duration to 120000ms +20ms
The function that is called to send a message to the peer:
public async sendMessageToPeer(peerMultiaddr: string, message: string) {
try {
console.log("Sending message to peer:", peerMultiaddr);
const stream = await this.node.dialProtocol(
multiaddr(peerMultiaddr),
"/chat/1.0.0"
);
const encoder = new TextEncoder();
const encodedMessage = encoder.encode(message);
await pipe(
[encodedMessage], // Source (an iterable of Uint8Array)
stream.sink // Sink (stream write)
);
console.log(`Message sent to ${peerMultiaddr}: ${message}`);
return true;
} catch (e) {
console.error("Failed to send message to peer:", e);
return false;
}
}
The listener that listen to the incoming messages from a peer:
this.node.handle("/chat/1.0.0", async ({ stream, connection }) => {
const publicKey = connection.remotePeer.toString();
console.log(`Received a connection from ${publicKey}`);
for await (const chunk of stream.source) {
const text = new TextDecoder().decode(chunk.subarray()); // Uint8ArrayList to Uint8Array
// check if this sender is new
if (!(await MyLocalStorage.contact.isContactExist(publicKey))) {
console.log("New contact added:", publicKey);
MyLocalStorage.contact.addContact(publicKey, "New Contact");
} else {
console.log("Contact already exists");
}
this.messageCallback(publicKey, text);
}
});
The multiaddress that the CLIENT_2 uses to send a message to the CLIENT_1:
Sending message to peer: /ip4/RELAY_PUBLIC_IP/tcp/9001/ws/p2p/12D3KooWBVtp5xk4eo5Ztc8b3iG7Nbco3btbtp8VzdKzHsSKL3Ly/p2p-circuit/webrtc/p2p/12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU
The error that I got in the CLIENT_2 when sending a message to the CLIENT_1:
Failed to send message to peer: TimeoutError: signal timed out
If the CLIENT_2 uses the following multiaddress of the CLIENT_1:
Sending message to peer: /ip4/RELAY_PUBLIC_IP/tcp/9001/ws/p2p/12D3KooWBVtp5xk4eo5Ztc8b3iG7Nbco3btbtp8VzdKzHsSKL3Ly/p2p-circuit/p2p/12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU
I got the following error:
Failed to send message to peer: LimitedConnectionError: Cannot open protocol stream on limited connection
Hi, this is an interesting error! You have two browser peers connected to each other via a limited connection! I have somewhat similar. In my opinion the limited connection is failing to upgrade. The upgrade is happing through the dcutr() (direct connection upgrade through relay)
And in my log I have the following:
libp2p:connection:outbound:3m487p1746006109043 incoming stream opened on /libp2p/dcutr +84ms
common.ts:122 libp2p:dcutr A receiving connect +0ms
common.ts:122 libp2p:dcutr B had no dialable multiaddrs +58ms
common.ts:122 libp2p:dcutr:error incoming DCUtR from 12D3KooWJpmUQgEuyevuLZ14qZg74R3QrMyuohq8Ddq4vtApGz2k failed +0ms InvalidMessageError: DCUtR connect message had no dialable multiaddrs
at DefaultDCUtRService.handleIncomingUpgrade (dcutr.ts:319:15)
so it seems like the dcutr service either can't read the multiaddress or there was no multiaddress delivered.
Please note when I connect Browser to Node it works but Browser to Browser doesn't and I got the mentioned error.
Did you make sure Browser B connects to Browser A with the correct multiaddress which contains:
/p2p-circuit/webrtc/p2p/
or did you dial the
/p2p-circuit/p2p/
address? Because this was my mistake.
if you connected to the second one from or to one of your browser your error might be understandable.
Also in your package.json of the client I see: "@libp2p/webrtc-star": "^7.0.0" webrtc-star is not in use anymore since a year or two.
I am wondering how did you connect the two browsers? Which exact address did you use?
I tried to deploy the relay-node on a different server and the problem solved. However, I tried to block the communication between the two peers using IPs to force them to use the relay but I got timeout. They were able to communicate with the relay but it seems the relay didn't relayed their messages.
I don't really understand which network setup you have.
E.g. if you have the relay on a public server and you are not using auto-tls or other secure websocket (or webrtc-direct) you don't have any chance to reach it from your browsers. Also browsers can't upgrade their connection.
So I'd suggest the following network setup to create some clarity:
- setup a test relay on your machine and connect two different browser to it. If browsers are connecting to each other via direct WebRTC transport or a relayed connection and your stream messages go through, all is good. Maybe also have a look at the libp2 examples https://github.com/libp2p/js-libp2p-examples (your example should be possible to be found there)
- put the relay on a public internet node (use auto-tls or webrtc-direct) connect your browsers, repeat the test (see auto-tls example)
Maybe not work with different networks in your cooperate lan at the moment since that is confusing the situation a bit.
I have a public server that I deployed the relay on it. Although, I am not using secure websocket I am running the client peers on a http://localhost so they should be able to reach the relay and send the messages to eachother. However, when one of the client peers is one a static public IP, the communication works but direct communication not relayed one. it seems to me the circute relay is not relaying the messages when there is a strict NAT between the peers. It only connect them to each other.
If you run a private browser "client" peer you need a (circuit) relay and a websocket (!) on your local relay (or a webrtc-direct) or a secure websocket on your public relay. A browser "client" peer cannot reach a relay by just tcp or quic! That is impossible.
If you run a private or public NodeJS "client" peer, it can reach the public relay without websocket, webrtc-direct but browsers can't.
Make sure you use a secure websocket (or WebRTC-direct) on your public relay so private browser peers can connect. Then circuit-relay will work behind NAT.
I used libp2p dev tool and got the following logs from the client which is sending the message:
Sending message to peer: /dns4/xx.xxxx.xx/tcp/9001/ws/p2p/12D3KooWRSBkaFfAAvxXYV2nqusTxZzrBNaTqma4Lhh1vt9BZTzb/p2p-circuit/webrtc/p2p/12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU Libp2pMessenger.ts:93:14
libp2p:connection-manager dial 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +0ms common.ts:122:12
libp2p:connection-manager:dial-queue creating dial target for 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +0ms
Array [ "/dns4/xx.xxxx.xx/tcp/9001/ws/p2p/12D3KooWRSBkaFfAAvxXYV2nqusTxZzrBNaTqma4Lhh1vt9BZTzb/p2p-circuit/webrtc/p2p/12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU" ]
common.ts:122:12
libp2p:connection-manager:dial-queue starting dial to 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +24ms common.ts:122:12
libp2p:connection-manager:dial-queue calculating addrs to dial 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU from /dns4/xx.xxxx.xx/tcp/9001/ws/p2p/12D3KooWRSBkaFfAAvxXYV2nqusTxZzrBNaTqma4Lhh1vt9BZTzb/p2p-circuit/webrtc/p2p/12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +0ms common.ts:122:12
libp2p:connection-manager:dial-queue starting dial to 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU with /dns4/xx.xxxx.xx/tcp/9001/ws/p2p/12D3KooWRSBkaFfAAvxXYV2nqusTxZzrBNaTqma4Lhh1vt9BZTzb/p2p-circuit/webrtc/p2p/12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +26ms common.ts:122:12
libp2p:circuit-relay:transport new outbound relayed connection /dns4/xx.xxxx.xx/tcp/9001/ws/p2p/12D3KooWRSBkaFfAAvxXYV2nqusTxZzrBNaTqma4Lhh1vt9BZTzb/p2p-circuit/p2p/12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +0ms common.ts:122:12
libp2p:stream:converter encrypting outbound connection to /dns4/xx.xxxx.xx/tcp/9001/ws/p2p/12D3KooWRSBkaFfAAvxXYV2nqusTxZzrBNaTqma4Lhh1vt9BZTzb/p2p-circuit/p2p/12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU using /noise +0ms common.ts:122:12
libp2p:stream:converter successfully upgraded outbound connection +547ms common.ts:122:12
libp2p:connection-manager:connection-pruner checking max connections limit 2/100 +0ms common.ts:122:12
libp2p:connection:outbound:dcme281746364005544 incoming stream opened on /ipfs/id/1.0.0 +0ms common.ts:122:12
libp2p:address-manager:observed-addresses adding observed address /dns4/xx.xxxx.xx/tcp/9001/ws/p2p/12D3KooWRSBkaFfAAvxXYV2nqusTxZzrBNaTqma4Lhh1vt9BZTzb/p2p-circuit +0ms common.ts:122:12
libp2p:identify identify completed for peer 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU and protocols
Array(5) [ "/chat/1.0.0", "/ipfs/id/1.0.0", "/ipfs/ping/1.0.0", "/libp2p/circuit/relay/0.2.0/stop", "/webrtc-signaling/0.0.1" ]
+0ms common.ts:122:12
libp2p:identify received identify from 12D3KooWBVsTi7XZz8cMp8v7fTgNVwCsPtDc6hq5FgBJ3WfB9rNU +1ms common.ts:122:12
WebRTC: ICE failed, add a TURN server and see about:webrtc for more details
libp2p:connection:outbound:cd55nx1746363935587 incoming stream opened on /ipfs/ping/1.0.0 +10s common.ts:122:12
libp2p:ping incoming ping from 12D3KooWRSBkaFfAAvxXYV2nqusTxZzrBNaTqma4Lhh1vt9BZTzb +10s common.ts:122:12
libp2p:ping incoming ping from 12D3KooWRSBkaFfAAvxXYV2nqusTxZzrBNaTqma4Lhh1vt9BZTzb complete in 498ms +498ms common.ts:122:12
libp2p:connection-manager:dial-queue:error error in dial queue - The operation timed out. +0ms common.ts:122:12
Failed to send message to peer: DOMException: The operation timed out.
It seems there is an error with the following
WebRTC: ICE failed, add a TURN server and see about:webrtc for more details
And the following error from the firefox about:webrtc
(ice/ERR) ICE(PC:{27383ae4-2e1f-408b-86e5-1ee6069f011f} 1746364006328000 (id=15032385539 url=http://localhost:5173/)): failed to find default addresses
(generic/CRIT) PR_Connect failed: -5980
I tried to use the following configuration for the webrtc to add a TRUN server:
webRTC({
rtcConfiguration: {
iceServers: [
{
urls: "stun:stun.l.google.com:19302", // Public STUN
},
{
urls: "turns:openrelay.metered.ca:443",
username: "openrelayproject",
credential: "openrelayproject",
},
],
},
}),
I got the following error:
WebRTC: ICE failed, your TURN server appears to be broken, see about:webrtc for more details
Then, I got a notification from the security team.
Do companies usually block the webRTC, if so what we can do if we want to sell our apps to them, should we deploy the TRUN server at their network?
Yes, some companies block WebRTC. But I wouldn't call this usual. In such cases use a secure websocket. Did you try auto-tls https://github.com/libp2p/js-libp2p-example-auto-tls ?
I have a similar stuff and i am facing this issue when my relay is publicly hosted and two peers are on different networks.
WebRTC: ICE failed, add a TURN server and see about:webrtc for more details
i had similar errors. i fixed this by allowing mdns in firewall rules on my machine.
not only webrtc transport in libp2p didn't work, but webrtc in general. web browsers obfuscate ice candidates by replacing local ip addresses with mdns hostnames (ending with .local) for privacy reasons, and the firewall blocked mdns traffic on my machine. (weirdly everything starts working if you allow microphone or camera permissions on the tab. that's because browsers don't obfuscate ip addresses in this case for some reason.)
trying to fix this bug for 4 days was wild