redis/node-redis · error · ClientClosedError
The client is closed
Error message
The client is closed
What it means
Thrown from RedisSocket.quit() (socket.ts:446) when the socket is not open. quit() is meant to gracefully close an active connection (it sends QUIT and waits for the reply), so calling it on an already-closed/never-opened client is a programming error. Throws ClientClosedError synchronously.
Source
Thrown at packages/client/lib/client/socket.ts:446
if (this.#socket.writableNeedDrain) break;
}
} catch (err) {
// net.Socket.write can throw synchronously on a half-closed socket
// (writeAfterFIN -> EPIPE) before the 'close' event fires. The pending
// command has already been moved to #waitingForReply by the queue's
// generator, so the close handler will reject it on reconnect.
if (!err || (err as NodeJS.ErrnoException).code !== 'EPIPE') {
throw err;
}
} finally {
this.#socket.uncork();
}
}
async quit<T>(fn: () => Promise<T>): Promise<T> {
if (!this.#isOpen) {
throw new ClientClosedError();
}
this.#isOpen = false;
const reply = await fn();
this.destroySocket();
return reply;
}
close() {
if (!this.#isOpen) {
throw new ClientClosedError();
}
this.#isOpen = false;
}
destroy() {
if (!this.#isOpen) {View on GitHub (pinned to bb5beb5657)
Solutions
- Check client.isOpen before calling quit().
- Use destroy() for forced shutdown that tolerates an already-closed state, or guard with try/catch.
- Drive shutdown from a single place to avoid racing quit()/close() calls.
Example fix
// before await client.quit(); // throws 'The client is closed' if already closed // after if (client.isOpen) await client.quit();
Defensive patterns
Strategy: validation
Validate before calling
if (client.isOpen) { await client.quit(); } Try / catch
try { await client.quit(); } catch (e) { if (!/client is closed/i.test(e.message)) throw e; } Prevention
- Check client.isOpen before quit().
- Own teardown in one place to avoid double shutdown.
- After a fatal 'error' event, prefer destroy() over quit().
When it happens
Trigger: Calling client.quit() after client.close()/destroy(), or on a client whose connection never established, or after an unexpected close already ran.
Common situations: Shutdown handlers calling quit() unconditionally; double shutdown in finally blocks; calling quit() after a fatal 'error' event already closed the socket.
Related errors
- Socket already opened
- TokenManager is not running, but refresh was called
- TokenManager is not running, but a new token was received
- TokenManager is not running but received an error: ${errorMe
- The client is closed
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/0a3aab2cbaed2dbd.json.
Report an issue: GitHub.