redis/node-redis · error · Error

Socket already opened

Error message

Socket already opened

What it means

Thrown by RedisSocket.connect() when #isOpen is already true. The socket permits exactly one connect() call per lifecycle; a second call indicates a logic error such as calling client.connect() twice or calling it on a client that auto-connected.

Solutions

  1. Guard the connect call: if (!client.isOpen) await client.connect().
  2. Centralize client creation and connection in one place and export the ready promise.
  3. Call client.disconnect() or client.destroy() before re-connecting if you truly need a fresh connection.
  4. Use a singleton pattern so connect() runs exactly once at app boot.

Example fix

// before
await client.connect();
await client.connect(); // throws 'Socket already opened'

// after
if (!client.isOpen) {
  await client.connect();
}
Defensive patterns

Strategy: validation

Validate before calling

if (client.isOpen) {
  // already connected, skip
} else {
  await client.connect();
}

Type guard

function shouldConnect(client: RedisClientType): boolean {
  return !client.isOpen;
}

Try / catch

try {
  await client.connect();
} catch (e) {
  if (e instanceof Error && e.message === 'Socket already opened') return;
  throw e;
}

Prevention

When it happens

Trigger: Calling await client.connect() a second time without an intervening close()/destroy(). Calling connect() inside a reconnect handler on a socket that is already open. Constructing a client with a url and calling connect() after the client already connected lazily for a pub/sub subscription.

Common situations: Hot-reload / HMR in dev frameworks double-invoking an init function; mis-ordered startup where connect() is called from two code paths; sharing a singleton client across modules where both call connect().

Related errors


AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11). Data as JSON: /api/errors/f75c3381fd4193b8. Report an issue: GitHub.

Appendix: source

Thrown at packages/client/lib/client/socket.ts:237

      return cause;
    } else if (retryIn instanceof Error) {
      this.#isOpen = false;
      publish(CHANNELS.ERROR, () => ({
        error: cause,
        origin: 'client',
        internal: false,
        clientId: this.#clientId
      }));
      this.emit('error', cause);
      return new ReconnectStrategyError(retryIn, cause);
    }

    return retryIn;
  }

  async connect(): Promise<void> {
    if (this.#isOpen) {
      throw new Error('Socket already opened');
    }

    this.#isOpen = true;
    return this.#connect();
  }

  async #connect(): Promise<void> {
    let retries = 0;
    do {
      try {
        const connectStartTime = performance.now();
        const socket = this.#socket = await this.#createSocket();
        this.emit('connect');

        try {
          await this.#initiateWhileSocketAlive(socket);

          // Check if socket was closed/destroyed during initiator execution

View on GitHub (pinned to 90fd0652bc)