redis/node-redis · error · TypeError

Reconnect strategy should return `false | Error | number`, g

Error message

Reconnect strategy should return `false | Error | number`, got ${retryIn} instead

What it means

Thrown inside the wrapped reconnectStrategy (socket.ts:125) when a user-supplied reconnectStrategy function returns a value that is not false | Error | number. The error is caught immediately (socket.ts:128), emitted on the socket/client 'error' event, published to the tracing channel, and the default exponential-backoff strategy takes over for that attempt — so it does NOT reject the connect()/command promise. It signals a misconfigured strategy.

Source

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

    this.#connectTimeout = options?.connectTimeout ?? 5000;
    this.#reconnectStrategy = this.#createReconnectStrategy(options);
    this.#socketFactory = this.#createSocketFactory(options);
    this.#socketTimeout = options?.socketTimeout;
    this.#clientId = clientId;
  }

  #createReconnectStrategy(options?: RedisSocketOptions): ReconnectStrategyFunction {
    const strategy = options?.reconnectStrategy;
    if (strategy === false || typeof strategy === 'number') {
      return () => strategy;
    }

    if (strategy) {
      return (retries, cause) => {
        try {
const retryIn = strategy(retries, cause);
          if (retryIn !== false && !(retryIn instanceof Error) && typeof retryIn !== 'number') {
            throw new TypeError(`Reconnect strategy should return \`false | Error | number\`, got ${retryIn} instead`);
          }
          return retryIn;
        } catch (err) {
          publish(CHANNELS.ERROR, () => ({
            error: err as Error,
            origin: 'client',
            internal: false,
            clientId: this.#clientId
          }));
          this.emit('error', err);
          return this.defaultReconnectStrategy(retries, err);
        }
      };
    }

    return this.defaultReconnectStrategy;
  }

View on GitHub (pinned to bb5beb5657)

Solutions

  1. Make the strategy return a number (ms delay), false (stop reconnecting), or an Error (stop with custom error) — nothing else.
  2. Attach a client.on('error', ...) listener so this surfaces clearly instead of as an unhandled error.
  3. For async-derived delays, compute the delay inside the function and return the resolved number synchronously.

Example fix

// before
const client = createClient({ socket: { reconnectStrategy: (retries) => `${retries * 100}` } }); // returns string -> TypeError

// after
const client = createClient({ socket: { reconnectStrategy: (retries) => retries * 100 } }); // returns number
Defensive patterns

Strategy: validation

Validate before calling

function isValidReturn(v: unknown): boolean {
  return v === false || v instanceof Error || typeof v === 'number';
}
// test the strategy in isolation before passing it:
for (let r = 0; r < 3; r++) assert.ok(isValidReturn(strategy(r, new Error('x'))));

Type guard

function isReconnectStrategyFn(v: unknown): v is (r: number, c: Error) => false | Error | number {
  return typeof v === 'function';
}

Try / catch

client.on('error', (e) => {
  if (/Reconnect strategy should return/.test(e.message)) {
    // log and fix the strategy; default backoff has taken over
  }
});

Prevention

When it happens

Trigger: Configure socket.reconnectStrategy as a function that returns e.g. a string ('500'), null, true, or a Promise. On the first reconnect attempt the bad return value triggers this TypeError, surfaced via the 'error' event.

Common situations: Returning a string delay instead of a number; returning undefined explicitly and assuming default; returning a Promise (async strategy); returning null on 'no retry'.

Related errors


AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03). Data as JSON: /data/errors/e653e1fa01f529b0.json. Report an issue: GitHub.