{"id":"e653e1fa01f529b0","repo":"redis/node-redis","slug":"reconnect-strategy-should-return-false-error","errorCode":null,"errorMessage":"Reconnect strategy should return `false | Error | number`, got ${retryIn} instead","messagePattern":"Reconnect strategy should return `false \\| Error \\| number`, got (.+?) instead","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/client/lib/client/socket.ts","lineNumber":125,"sourceCode":"    this.#connectTimeout = options?.connectTimeout ?? 5000;\n    this.#reconnectStrategy = this.#createReconnectStrategy(options);\n    this.#socketFactory = this.#createSocketFactory(options);\n    this.#socketTimeout = options?.socketTimeout;\n    this.#clientId = clientId;\n  }\n\n  #createReconnectStrategy(options?: RedisSocketOptions): ReconnectStrategyFunction {\n    const strategy = options?.reconnectStrategy;\n    if (strategy === false || typeof strategy === 'number') {\n      return () => strategy;\n    }\n\n    if (strategy) {\n      return (retries, cause) => {\n        try {\nconst retryIn = strategy(retries, cause);\n          if (retryIn !== false && !(retryIn instanceof Error) && typeof retryIn !== 'number') {\n            throw new TypeError(`Reconnect strategy should return \\`false | Error | number\\`, got ${retryIn} instead`);\n          }\n          return retryIn;\n        } catch (err) {\n          publish(CHANNELS.ERROR, () => ({\n            error: err as Error,\n            origin: 'client',\n            internal: false,\n            clientId: this.#clientId\n          }));\n          this.emit('error', err);\n          return this.defaultReconnectStrategy(retries, err);\n        }\n      };\n    }\n\n    return this.defaultReconnectStrategy;\n  }\n","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/redis/node-redis/blob/bb5beb56578573910e2ee8f39681edc214c41398/packages/client/lib/client/socket.ts#L107-L143","documentation":"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.","triggerScenarios":"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.","commonSituations":"Returning a string delay instead of a number; returning undefined explicitly and assuming default; returning a Promise (async strategy); returning null on 'no retry'.","solutions":["Make the strategy return a number (ms delay), false (stop reconnecting), or an Error (stop with custom error) — nothing else.","Attach a client.on('error', ...) listener so this surfaces clearly instead of as an unhandled error.","For async-derived delays, compute the delay inside the function and return the resolved number synchronously."],"exampleFix":"// before\nconst client = createClient({ socket: { reconnectStrategy: (retries) => `${retries * 100}` } }); // returns string -> TypeError\n\n// after\nconst client = createClient({ socket: { reconnectStrategy: (retries) => retries * 100 } }); // returns number","handlingStrategy":"validation","validationCode":"function isValidReturn(v: unknown): boolean {\n  return v === false || v instanceof Error || typeof v === 'number';\n}\n// test the strategy in isolation before passing it:\nfor (let r = 0; r < 3; r++) assert.ok(isValidReturn(strategy(r, new Error('x'))));","typeGuard":"function isReconnectStrategyFn(v: unknown): v is (r: number, c: Error) => false | Error | number {\n  return typeof v === 'function';\n}","tryCatchPattern":"client.on('error', (e) => {\n  if (/Reconnect strategy should return/.test(e.message)) {\n    // log and fix the strategy; default backoff has taken over\n  }\n});","preventionTips":["Always attach a client.on('error') listener — this error is emitted, not thrown to callers.","Return only number|false|Error from the strategy; never a string or Promise.","Unit-test the strategy's return values for retries 0..N."],"tags":["reconnect","configuration","typescript","socket"],"analyzedSha":"bb5beb56578573910e2ee8f39681edc214c41398","analyzedAt":"2026-08-03T19:09:15.686Z","schemaVersion":2}