{"record":{"id":"bdad47fdd32b60e0","repo":"cube-js/cube","slug":"cube-store-connection-is-closed","errorCode":null,"errorMessage":"Cube Store connection is closed","messagePattern":"Cube Store connection is closed","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-cubestore-driver/src/WebSocketConnection.ts","lineNumber":120,"sourceCode":"  // messages that were still in flight at that point.\n  private closedAt: Date | null = null;\n\n  public constructor(url: string) {\n    this.url = url;\n    this.messageCounter = 1;\n    this.maxConnectRetries = getEnv('cubeStoreMaxConnectRetries');\n    this.noHeartBeatTimeout = getEnv('cubeStoreNoHeartBeatTimeout');\n    this.maxMessageSize = getEnv('cubeStoreMaxMessageSize');\n    this.currentConnectionTry = 0;\n    this.connectionId = uuidv4();\n  }\n\n  protected async initWebSocket(): Promise<CubeStoreWebSocket> {\n    if (this.closed) {\n      // Refusing here is what makes close() terminal: it covers a query issued\n      // after the release as well as the re-send path, whose `catch` then\n      // rejects the messages that were in flight instead of re-opening for them.\n      throw new ConnectionError('Cube Store connection is closed');\n    }\n\n    if (!this.webSocket) {\n      const headers: Record<string, string> = {};\n      headers['x-process-id'] = getProcessUid();\n\n      const webSocket = new WebSocket(this.url, { headers, maxPayload: this.maxMessageSize }) as CubeStoreWebSocket;\n      webSocket.on('upgrade', (response: any) => {\n        this.cubeStoreVersion = response.headers['x-cubestore-version'] || null;\n      });\n\n      webSocket.readyPromise = new Promise<CubeStoreWebSocket>((resolve, reject) => {\n        webSocket.lastHeartBeat = new Date();\n        const pingInterval = setInterval(() => {\n          if (webSocket.readyState === WebSocket.OPEN) {\n            webSocket.ping();\n          }\n","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-cubestore-driver/src/WebSocketConnection.ts#L102-L138","documentation":"WebSocketConnection.initWebSocket refuses to open a new WebSocket after the connection has been closed via close(), throwing a ConnectionError. This makes close terminal: any query issued after release is rejected instead of silently re-opening a socket. In-flight messages on the re-send path are also rejected with this error.","triggerScenarios":"Calling driver.query()/release() or re-sending a queued message after WebSocketConnection.close() has been called; using a driver after its connection was released (e.g. after pool teardown or process shutdown).","commonSituations":"App shutting down while queries are still queued; a query orchestrator retrying a request after the Cube Store connection was released; holding a driver reference past its lifecycle in tests.","solutions":["Ensure queries complete before calling close()/release()","Re-create the driver/connection instead of reusing a closed one","Add readiness checks before dispatching queries during shutdown","In tests, scope driver lifetime to the test and close last"],"exampleFix":"// before\nconnection.close();\nawait connection.query('SELECT 1', []); // throws ConnectionError\n// after\nawait connection.query('SELECT 1', []);\nconnection.close();","handlingStrategy":"try-catch","validationCode":"// track lifecycle in a wrapper\nlet released = false;\nconst guard = (conn) => { if (released) throw new Error('driver already released'); return conn; };","typeGuard":"const isConnectionClosed = (e) => e instanceof ConnectionError && /connection is closed/i.test(e.message);","tryCatchPattern":"try {\n  await driver.query(sql, params);\n} catch (e) {\n  if (isConnectionClosed(e)) {\n    driver = createDriver(); // recreate instead of reusing closed connection\n    return driver.query(sql, params);\n  }\n  throw e;\n}","preventionTips":["Close/release connections only after all queries settle","Track connection lifecycle explicitly (e.g. a released flag)","Scope driver lifetime per request or per app, not shared after teardown","In tests, always close drivers in afterAll, not between assertions"],"tags":["cubestore","websocket","connection-lifecycle"],"backgroundTag":"connection-closed","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}