Troubleshooting connection issues

Common/known issues:

Problem: the socket is not able to connect

Possible explanations:

You are trying to reach a plain WebSocket server

As explained in the “What Socket.IO is not” section, the Socket.IO client is not a WebSocket implementation and thus will not be able to establish a connection with a WebSocket server, even with transports: ["websocket"]:

const socket = io("ws://echo.websocket.org", {
  transports: ["websocket"]
});

The server is not reachable

Please make sure the Socket.IO server is actually reachable at the given URL. You can test it with:

curl "<the server URL>/socket.io/?EIO=4&transport=polling"

which should return something like this:

0{"sid":"Lbo5JLzTotvW3g2LAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":20000}

If that’s not the case, please check that the Socket.IO server is running, and that there is nothing in between that prevents the connection.

The client is not compatible with the version of the server

Here is the compatibility table for the JS client:

JS Client version Socket.IO server version
1.x 2.x 3.x 4.x
1.x YES NO NO NO
2.x NO YES YES1 YES1
3.x NO NO YES YES
4.x NO NO YES YES

[1] Yes, with allowEIO3: true

Here is the compatibility table for the Java client:

Java Client version Socket.IO server version
2.x 3.x 4.x
1.x YES YES1 YES1
2.x NO YES YES

[1] Yes, with allowEIO3: true

Here is the compatibility table for the Swift client:

Swift Client version Socket.IO server version
2.x 3.x 4.x
v15.x YES YES1 YES2
v16.x YES3 YES YES

[1] Yes, with allowEIO3: true (server) and .connectParams(["EIO": "3"]) (client):

SocketManager(socketURL: URL(string:"http://localhost:8087/")!, config: [.connectParams(["EIO": "3"])])

[2] Yes, allowEIO3: true (server)

[3] Yes, with .version(.two) (client):

SocketManager(socketURL: URL(string:"http://localhost:8087/")!, config: [.version(.two)])

The server does not send the necessary CORS headers

If you see the following error in your console:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ...

It probably means that:

Please see the documentation here.

You didn’t enable sticky sessions (in a multi server setup)

When scaling to multiple Socket.IO servers, you need to make sure that all the requests of a given Socket.IO session reach the same Socket.IO server. The explanation can be found here.

Failure to do so will result in HTTP 400 responses with the code: {"code":1,"message":"Session ID unknown"}

Please see the documentation here.

Problem: the socket gets disconnected

First and foremost, please note that disconnections are common and expected, even on a stable Internet connection:

  • anything between the user and the Socket.IO server may encounter a temporary failure or be restarted
  • the server itself may be killed as part of an autoscaling policy
  • the user may lose connection or switch from WiFi to 4G, in case of a mobile browser
  • the browser itself may freeze an inactive tab

That being said, the Socket.IO client will always try to reconnect, unless specifically told otherwise.

Possible explanations:

You are trying to send a huge payload

If you get disconnected while sending a huge payload, this may mean that you have reached the maxHttpBufferSize value, which defaults to 1 MB. Please adjust it according to your needs:

const io = require("socket.io")(httpServer, {
  maxHttpBufferSize: 1e8
});

A huge payload taking more time to upload than the value of the pingTimeout option can also trigger a disconnection (since the heartbeat mechanism fails during the upload). Please adjust it according to your needs:

const io = require("socket.io")(httpServer, {
  pingTimeout: 60000
});

Problem: the socket is stuck in HTTP long-polling

In most cases, you should see something like this:

Network monitor upon success

  1. the Engine.IO handshake (contains the session ID — here, zBjrh...AAAK — that is used in subsequent requests)
  2. the Socket.IO handshake request (contains the value of the auth option)
  3. the Socket.IO handshake response (contains the Socket#id)
  4. the WebSocket connection
  5. the first HTTP long-polling request, which is closed once the WebSocket connection is established

If you don’t see a HTTP 101 Switching Protocols response for the 4th request, that means that something between the server and your browser is preventing the WebSocket connection.

Please note that this is not necessarily blocking since the connection is still established with HTTP long-polling, but it is less efficient.

You can get the name of the current transport with:

Client-side

socket.on("connect", () => {
  const transport = socket.io.engine.transport.name; // in most cases, "polling"

  socket.io.engine.on("upgrade", () => {
    const upgradedTransport = socket.io.engine.transport.name; // in most cases, "websocket"
  });
});

Server-side

io.on("connection", (socket) => {
  const transport = socket.conn.transport.name; // in most cases, "polling"

  socket.conn.on("upgrade", () => {
    const upgradedTransport = socket.conn.transport.name; // in most cases, "websocket"
  });
});

Possible explanations:

A proxy in front of your servers does not accept the WebSocket connection

Please see the documentation here.

© 2014–2021 Automattic
Licensed under the MIT License.
https://socket.io/docs/v4/troubleshooting-connection-issues