{"id":"0a3aab2cbaed2dbd","repo":"redis/node-redis","slug":"the-client-is-closed-0a3aab","errorCode":null,"errorMessage":"The client is closed","messagePattern":"The client is closed","errorType":"exception","errorClass":"ClientClosedError","httpStatus":null,"severity":"error","filePath":"packages/client/lib/client/socket.ts","lineNumber":446,"sourceCode":"\n        if (this.#socket.writableNeedDrain) break;\n      }\n    } catch (err) {\n      // net.Socket.write can throw synchronously on a half-closed socket\n      // (writeAfterFIN -> EPIPE) before the 'close' event fires. The pending\n      // command has already been moved to #waitingForReply by the queue's\n      // generator, so the close handler will reject it on reconnect.\n      if (!err || (err as NodeJS.ErrnoException).code !== 'EPIPE') {\n        throw err;\n      }\n    } finally {\n      this.#socket.uncork();\n    }\n  }\n\n  async quit<T>(fn: () => Promise<T>): Promise<T> {\n    if (!this.#isOpen) {\n      throw new ClientClosedError();\n    }\n\n    this.#isOpen = false;\n    const reply = await fn();\n    this.destroySocket();\n    return reply;\n  }\n\n  close() {\n    if (!this.#isOpen) {\n      throw new ClientClosedError();\n    }\n\n    this.#isOpen = false;\n  }\n\n  destroy() {\n    if (!this.#isOpen) {","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/redis/node-redis/blob/bb5beb56578573910e2ee8f39681edc214c41398/packages/client/lib/client/socket.ts#L428-L464","documentation":"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.","triggerScenarios":"Calling client.quit() after client.close()/destroy(), or on a client whose connection never established, or after an unexpected close already ran.","commonSituations":"Shutdown handlers calling quit() unconditionally; double shutdown in finally blocks; calling quit() after a fatal 'error' event already closed the socket.","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."],"exampleFix":"// before\nawait client.quit(); // throws 'The client is closed' if already closed\n\n// after\nif (client.isOpen) await client.quit();","handlingStrategy":"validation","validationCode":"if (client.isOpen) { await client.quit(); }","typeGuard":null,"tryCatchPattern":"try { await client.quit(); } catch (e) { if (!/client is closed/i.test(e.message)) throw e; }","preventionTips":["Check client.isOpen before quit().","Own teardown in one place to avoid double shutdown.","After a fatal 'error' event, prefer destroy() over quit()."],"tags":["lifecycle","shutdown","socket"],"analyzedSha":"bb5beb56578573910e2ee8f39681edc214c41398","analyzedAt":"2026-08-03T19:09:15.686Z","schemaVersion":2}