redis
semver
>=5.0.0 <7.0.0postconditions28functions27last verified2026-06-23coverage score100%Postconditions — what we check
- createClient · missing-error-listenererrorWhencreateClient() called without .on('error', handler) registeredRequired handlingMUST call client.on('error', handler) immediately after createClient(). Handler should log error details and optionally trigger reconnection logic or graceful shutdown.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1]
- connect · connect-no-error-handlingerrorWhenclient.connect() called without try-catch or .catch() handlerThrows
Connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN)Required handlingMUST wrap await client.connect() in try-catch block. Catch block should check error.code and implement retry logic with exponential backoff for recoverable errors. Non-recoverable errors should trigger graceful shutdown or fallback mode.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - get · get-no-error-handlingerrorWhenclient.get() called without try-catch or .catch() handlerThrows
Connection errors, timeout errors, or WRONGTYPE errorsRequired handlingMUST wrap await client.get() in try-catch block. For connection errors, implement graceful degradation (fallback to database). For WRONGTYPE errors, fix data schema. For timeout errors, retry with backoff or return cached/default value.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - set · set-no-error-handlingerrorWhenclient.set() called without try-catch or .catch() handlerThrows
Connection errors, timeout errors, or command errorsRequired handlingMUST wrap await client.set() in try-catch block. For connection errors, consider queueing write for retry. For critical writes, re-throw error to caller. For non-critical cache writes, log error and continue without cache.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - del · del-no-error-handlingerrorWhenclient.del() called without try-catch or .catch() handlerThrows
Connection errors or timeout errorsRequired handlingMUST wrap await client.del() in try-catch block. For connection errors, log error and decide whether to retry, fail operation, or continue. Critical deletes should re-throw error to caller for proper handling.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - hSet · hset-no-error-handlingerrorWhenclient.hSet() called without try-catch or .catch() handlerThrows
ErrorReply (WRONGTYPE when key exists as non-hash), connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN), SocketClosedUnexpectedlyErrorRequired handlingMUST wrap await client.hSet() in try-catch. Check err.message.includes('WRONGTYPE') to distinguish type errors from connection errors. Type errors indicate a data schema bug; connection errors may be retried.costmediumin prodimmediate exceptionusers seelost datavisibilityvisible - hGet · hget-no-error-handlingerrorWhenclient.hGet() called without try-catch or .catch() handlerThrows
ErrorReply (WRONGTYPE if key is not a hash), connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN)Required handlingMUST wrap await client.hGet() in try-catch. Return null fallback for missing fields is correct — do not confuse this with thrown errors.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - hGetAll · hgetall-no-error-handlingerrorWhenclient.hGetAll() called without try-catch or .catch() handlerThrows
ErrorReply (WRONGTYPE if key is not a hash), connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN)Required handlingMUST wrap in try-catch. Also check if the returned object is empty ({}) to detect missing sessions/profiles — returning {} is not an error but often indicates "not found" semantics.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - incr · incr-no-error-handlingerrorWhenclient.incr() called without try-catch or .catch() handlerThrows
ErrorReply ("ERR value is not an integer or out of range") when key holds a non-integer string; connection errors (ECONNREFUSED, ETIMEDOUT)Required handlingMUST wrap await client.incr() in try-catch. Check err.message for "not an integer" to distinguish type errors (data schema bug) from connection errors (retriable).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - incrBy · incrby-no-error-handlingerrorWhenclient.incrBy() called without try-catch or .catch() handlerThrows
ErrorReply ("ERR value is not an integer or out of range") when key holds a non-integer; connection errors (ECONNREFUSED, ETIMEDOUT)Required handlingMUST wrap await client.incrBy() in try-catch. Same handling as incr().costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - expire · expire-no-error-handlingerrorWhenclient.expire() called without try-catch or .catch() handlerThrows
Connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN); ErrorReply on invalid argument typesRequired handlingMUST wrap await client.expire() in try-catch. Prefer atomic client.set(key, value, {EX: ttl}) to avoid the set-then-expire race condition entirely. If separate expire() is required, log and alert on failure — persistent keys are a security and memory risk.costmediumin prodimmediate exceptionusers seedegraded performancevisibilitysilent - exists · exists-no-error-handlingerrorWhenclient.exists() called without try-catch or .catch() handlerThrows
Connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN)Required handlingMUST wrap await client.exists() in try-catch. Distinguish connection errors from logic errors. For cache-pattern guards, fail safe (treat as "not exists" and proceed to authoritative source).costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - lPush · lpush-no-error-handlingerrorWhenclient.lPush() called without try-catch or .catch() handlerThrows
ErrorReply (WRONGTYPE if key is not a list), connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN)Required handlingMUST wrap await client.lPush() in try-catch. For queue patterns, re-throw so callers can handle job failure. Check err.message.includes('WRONGTYPE') to detect key type collisions.costmediumin prodimmediate exceptionusers seelost datavisibilityvisible - lRange · lrange-no-error-handlingerrorWhenclient.lRange() called without try-catch or .catch() handlerThrows
ErrorReply (WRONGTYPE if key is not a list), connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN)Required handlingMUST wrap await client.lRange() in try-catch. An empty array is a valid result, not an error condition. Check for ErrorReply type to distinguish Redis server errors from connection errors.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - sAdd · sadd-no-error-handlingerrorWhenclient.sAdd() called without try-catch or .catch() handlerThrows
ErrorReply (WRONGTYPE if key is not a set), connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN)Required handlingMUST wrap await client.sAdd() in try-catch. For deduplication, re-throw on error to prevent silent data loss. Log WRONGTYPE errors — they indicate a key namespace collision that requires investigation.costmediumin prodimmediate exceptionusers seelost datavisibilityvisible - sMembers · smembers-no-error-handlingerrorWhenclient.sMembers() called without try-catch or .catch() handlerThrows
ErrorReply (WRONGTYPE if key is not a set), connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN)Required handlingMUST wrap await client.sMembers() in try-catch. An empty Set is a valid result. WRONGTYPE errors indicate data schema problems requiring code investigation.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - zAdd · zadd-no-error-handlingerrorWhenclient.zAdd() called without try-catch or .catch() handlerThrows
ErrorReply (WRONGTYPE if key is not a sorted set; "not a float" if score is NaN/Infinity), connection errors (ECONNREFUSED, ETIMEDOUT)Required handlingMUST wrap await client.zAdd() in try-catch. Validate score is a finite number before passing to zAdd(). WRONGTYPE indicates a key collision; score errors indicate a computation bug upstream.costmediumin prodimmediate exceptionusers seelost datavisibilityvisible - zRange · zrange-no-error-handlingerrorWhenclient.zRange() called without try-catch or .catch() handlerThrows
ErrorReply (WRONGTYPE if key is not a sorted set), connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN)Required handlingMUST wrap await client.zRange() in try-catch. An empty array is a valid result. Implement fallback for connection errors in leaderboard reads (return cached or empty data rather than throwing to the user).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - exec · multi-exec-watch-errorerrorWhenclient.watch() was used and the watched key was modified by another client before exec() was called; or client reconnected after WATCHThrows
WatchError (from @redis/client) — thrown from exec() when optimistic locking fails. The transaction was not executed.Required handlingMUST wrap exec() in try-catch when WATCH is used. Check err instanceof WatchError to implement retry logic. WatchError means the transaction was not executed — not a partial execution. Retry the full WATCH+MULTI+EXEC sequence.costmediumin prodimmediate exceptionusers seelost datavisibilityvisible - exec · multi-exec-connection-errorerrorWhenConnection is lost or client is closed before exec() completesThrows
SocketClosedUnexpectedlyError, ClientClosedError, or connection system errors (ECONNREFUSED, ECONNRESET)Required handlingMUST wrap exec() in try-catch. On connection error, the transaction state is unknown — implement reconciliation logic or re-read state before retrying.costmediumin prodimmediate exceptionusers seelost datavisibilityvisible - subscribe · subscribe-no-error-handlingerrorWhenclient.subscribe() called without try-catch or .catch() handlerThrows
ClientClosedError (if client is not connected), connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET) on network failure during subscriptionRequired handlingMUST wrap await client.subscribe() in try-catch for connection failure. The client .on('error') listener handles ongoing connection errors after subscription. Both patterns are required: try-catch for subscribe() AND .on('error') on client.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - publish · publish-no-error-handlingerrorWhenclient.publish() called without try-catch or .catch() handlerThrows
Connection errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN); ClientClosedError if client is disconnectedRequired handlingMUST wrap await client.publish() in try-catch. A return value of 0 is NOT an error — do not throw or retry based on the count alone. Only throw on connection errors or when guaranteed delivery is required (use a different pattern such as streams for guaranteed delivery).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - quit · quit-no-error-handlingwarningWhenclient.quit() called without try-catch or .catch() handlerThrows
Connection errors if the connection is already closed or lost before QUIT completes; SocketClosedUnexpectedlyErrorRequired handlingSHOULD wrap await client.quit() in try-catch in shutdown handlers. Errors during quit() can be logged and swallowed — the connection is being torn down anyway. Use `client.quit().catch(err => logger.warn('Redis quit error', err))` pattern.costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible - close · close-no-error-handlingwarningWhenclient.close() called without try-catch or .catch() handlerThrows
ClientClosedError if close() is called twice; connection-layer errors (ECONNRESET, ETIMEDOUT) if the socket dies during the graceful drain; unhandled promise rejection on any of the aboveRequired handlingSHOULD wrap await client.close() in try-catch in shutdown handlers. Errors during close() can be logged and swallowed — the connection is being torn down anyway. Use the same pattern as quit(): `client.close().catch(err => logger.warn('Redis close error', err))`. For graceful shutdown sequencing, await close() before terminating the process so pending commands flush.costlowin prodimmediate exceptionusers seedegraded performancevisibilityvisible - watch · watch-no-error-handlingerrorWhenclient.watch() called without try-catch or .catch() handlerThrows
Connection-layer errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, EAI_AGAIN); ClientClosedError if the client was closed before watch() ranRequired handlingMUST wrap await client.watch() in try-catch. On error, ABORT the entire transaction — do NOT proceed to multi().exec(). The exec() WatchError handler covers the "watched key changed" case; this handler covers the "watch() itself failed" case. Both are required for correct optimistic locking. Pattern: try { await client.watch('counter'); const value = await client.get('counter'); await client.multi().set('counter', String(Number(value) + 1)).exec(); } catch (err) { if (err instanceof WatchError) { /* retry: key changed */ } else { /* abort: watch or exec failed */ } }costmediumin prodimmediate exceptionusers seelost datavisibilityvisible - createClientPool · create-client-pool-no-error-handlingerrorWhencreateClientPool() factory called without a corresponding pool.on('error') listener AND without try-catch on the subsequent pool.connect()Throws
pool.connect() throws on connection failure (ECONNREFUSED, ETIMEDOUT, DNS failures); pool runtime errors are dispatched as 'error' events on the pool — uncaught events crash the process by defaultRequired handlingMUST register pool.on('error', handler) BEFORE calling pool.connect(), and MUST wrap await pool.connect() in try-catch. Pattern mirrors the createClient() / connect() / .on('error') triad — same rules apply.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - execute · pool-execute-no-error-handlingerrorWhenpool.execute(callback) called without try-catch or .catch() handlerThrows
WatchError (when callback uses WATCH+MULTI and the watched key was modified); any error thrown by the callback itself; connection-layer errors on the isolated client (ECONNREFUSED, ECONNRESET); ClientClosedError if the pool is closed mid-executeRequired handlingMUST wrap await pool.execute(...) in try-catch. Discriminate by error type: WatchError → retry the callback (the watched key changed, this is the designed retry signal). Other errors → fail the operation and log. The isolated client is returned to the pool regardless of outcome — do NOT attempt to close it inside the callback. Pattern: try { await pool.execute(async (client) => { await client.watch('key'); const v = await client.get('key'); return client.multi().set('key', updated(v)).exec(); }); } catch (err) { if (err instanceof WatchError) { /* retry */ } else { throw err; } }costmediumin prodimmediate exceptionusers seelost datavisibilityvisibleSources[14] - sendCommand · send-command-no-error-handlingerrorWhenclient.sendCommand() called without try-catch or .catch() handlerThrows
ErrorReply / SimpleError when Redis returns an error response (WRONGTYPE, NOSCRIPT, READONLY, MOVED, ASK, MASTERDOWN, etc.); connection-layer errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET); ClientClosedError if the client is disconnected; AbortError if an AbortSignal was attached and abortedRequired handlingMUST wrap await client.sendCommand() in try-catch. Inspect err.name === 'ReplyError' to handle Redis-level errors (WRONGTYPE, NOSCRIPT, etc.) distinctly from connection-layer errors. If using AbortSignal, also handle AbortError. For commands that mutate state, the safe pattern is: catch → log → re-raise so the caller can decide whether to retry or fail the request.costmediumin prodimmediate exceptionusers seelost datavisibilitysilentSources[1]
Sources
Every postcondition cites at least one of these. Numbered to match the footnotes above.
- [1]redis.io/docs/latesthttps://redis.io/docs/latest/develop/clients/nodejs/error-handling/
- [2]redis.io/commands/hsethttps://redis.io/commands/hset/
- [3]redis.io/commands/hgethttps://redis.io/commands/hget/
- [4]redis.io/commands/hgetallhttps://redis.io/commands/hgetall/
- [5]redis.io/commands/incrhttps://redis.io/commands/incr/
- [6]redis.io/commands/incrbyhttps://redis.io/commands/incrby/
- [7]redis.io/commands/expirehttps://redis.io/commands/expire/
- [8]redis.io/commands/lpushhttps://redis.io/commands/lpush/
- [9]redis.io/commands/lrangehttps://redis.io/commands/lrange/
- [10]redis.io/commands/saddhttps://redis.io/commands/sadd/
- [11]redis.io/commands/smembershttps://redis.io/commands/smembers/
- [12]redis.io/commands/zaddhttps://redis.io/commands/zadd/
- [13]redis.io/commands/zrangehttps://redis.io/commands/zrange/
- [14]redis.io/docs/latesthttps://redis.io/docs/latest/develop/clients/nodejs/transpipe/
- [15]redis.io/commands/watchhttps://redis.io/commands/watch/
- [16]redis.io/commands/subscribehttps://redis.io/commands/subscribe/
- [17]redis.io/commands/publishhttps://redis.io/commands/publish/
- [18]redis.io/commands/quithttps://redis.io/commands/quit/
- [19]github.com/redis/node-redishttps://github.com/redis/node-redis/blob/master/docs/v4-to-v5.md
Need a different package?
Request a profile