redis/node-redis · error · TypeError
Reconnect strategy should return `false | Error | number`…
Error message
Reconnect strategy should return `false | Error | number`, got ${retryIn} instead What it means
Thrown inside the wrapped reconnectStrategy when the user-supplied function returns a value that is not false, an Error, or a number. The library validates the return type on every reconnect decision because an invalid delay would break the backoff loop. The thrown TypeError is caught internally, emitted as an 'error' event, and the default strategy is used as a fallback.
Solutions
- Make the custom reconnectStrategy return a number (ms delay), false (stop reconnecting), or an Error (stop with error) — nothing else.
- If using a string from config, coerce with Number() and validate before returning.
- Ensure the function is synchronous; do not return a Promise.
- Listen for the 'error' event to confirm whether the fallback default strategy took over.
Example fix
// before
reconnectStrategy(retries) {
return retries < 10 ? '500' : false; // string -> TypeError
}
// after
reconnectStrategy(retries) {
return retries < 10 ? 500 : false; // number | false
} Defensive patterns
Strategy: validation
Validate before calling
function validStrategy(retries: number, cause: Error): false | Error | number {
const delay = Math.min(retries * 50, 2000);
return delay;
}
// test: assert typeof validStrategy(0,new Error()) === 'number' || v === false || v instanceof Error Type guard
function isValidReconnectReturn(v: unknown): v is false | Error | number {
return v === false || v instanceof Error || typeof v === 'number';
} Prevention
- Always return a number, false, or an Error from reconnectStrategy — never a string or undefined.
- Keep the strategy synchronous; do not return a Promise.
- Unit-test the strategy function over edge inputs.
When it happens
Trigger: Passing socket: { reconnectStrategy(retries, cause) { return '500'; } } (string), or returning null, undefined, a Promise, or NaN from the custom strategy function. Any non-(false|Error|number) return triggers it.
Common situations: Typo in a custom strategy returning a string like '500' instead of 500; returning retryIn > someMax as a boolean expression that evaluates to undefined; migrating from an older client whose strategy contract differed; returning a Promise instead of a plain value.
Related errors
- topologyRefreshOnReconnectionAttempt must be undefined…
- topologyRefreshOnReconnectionAttempt should return `false |…
- FILTER was given an empty filter expression list; omit it…
- is not a valid redis version
- All statistics values must be non-negative
AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11).
Data as JSON: /api/errors/e653e1fa01f529b0.
Report an issue: GitHub.
Appendix: 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 90fd0652bc)