Socket.IO "Error: xhr poll error" in CI tests
Socket.IO opens its first connection over HTTP long-polling. "xhr poll error" is emitted on connect_error when that initial poll request fails, so the transport never upgrades and the test client never connects.
What this error means
A test fails when the client emits connect_error with err.message === "xhr poll error". It reproduces intermittently: the server sometimes has not finished binding its port when the client dials.
Error: xhr poll error
at XHR.onError (node_modules/engine.io-client/build/cjs/transport.js:...)
at Request.<anonymous> (node_modules/engine.io-client/build/cjs/transports/polling-xhr.js:...)Common causes
The test server is not listening yet
The client io(url) runs before httpServer.listen(...) has bound the port, so the polling request is refused and Socket.IO reports it as an xhr poll error.
Wrong URL, path, or port in the test
A hardcoded port that differs from the one the server bound, or a custom path the server does not serve, makes every poll request fail.
How to fix it
Wait for the server to listen before connecting
- Bind the server on an ephemeral port and read the actual port back.
- Only create the client inside the
listencallback (or afterawaiton it). - Point the client at the real bound port.
await new Promise((res) => httpServer.listen(0, res));
const port = httpServer.address().port;
const client = io(`http://localhost:${port}`);Match the server path and transports
If the server sets a custom path, pass the same path to the client so the poll target exists.
const client = io(url, { path: '/socket', transports: ['websocket', 'polling'] });How to prevent it
- Start the server on port 0 and read back the assigned port in tests.
- Never hardcode a port that a parallel job may also bind.
- Create the client only after the server is confirmed listening.