{"record":{"id":"90729bb10380d19e","repo":"hcengineering/platform","slug":"closed-workspace","errorCode":null,"errorMessage":"Closed workspace","messagePattern":"Closed workspace","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"foundations/server/packages/server/src/sessionManager.ts","lineNumber":1280,"sourceCode":"    await this.workspaceProducer.close()\n    await this.usersProducer.close()\n  }\n\n  private async performWorkspaceCloseCheck (workspace: Workspace): Promise<void> {\n    const uuid = workspace.wsId.uuid\n    const logParams = { uuid, url: workspace.wsId.url }\n    if (workspace.sessions.size === 0) {\n      if (LOGGING_ENABLED) {\n        this.ctx.warn('no sessions for workspace', logParams)\n      }\n      try {\n        if (workspace.sessions.size === 0) {\n          await workspace.close(this.ctx)\n\n          this.workspaces.delete(uuid)\n          workspace.context.end()\n          if (LOGGING_ENABLED) {\n            this.ctx.warn('Closed workspace', logParams)\n          }\n\n          await this.workspaceProducer.send(this.ctx, workspace.wsId.uuid, [workspaceEvents.down()])\n        }\n      } catch (err: any) {\n        Analytics.handleError(err)\n        this.workspaces.delete(uuid)\n        if (LOGGING_ENABLED) {\n          this.ctx.error('failed', { ...logParams, error: err })\n        }\n      }\n    } else {\n      if (LOGGING_ENABLED) {\n        this.ctx.info('few sessions for workspace, close skipped', {\n          ...logParams,\n          sessions: workspace.sessions.size\n        })\n      }","sourceCodeStart":1262,"sourceCodeEnd":1298,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/server/packages/server/src/sessionManager.ts#L1262-L1298","documentation":"TSessionManager logs 'Closed workspace' after successfully calling workspace.close(this.ctx), deleting the workspace from this.workspaces, ending its context, and publishing a workspace down event. It confirms an idle (zero-session) workspace was fully torn down. It is informational, and marks the point after which pending operations targeting that workspace will fail because it no longer exists.","triggerScenarios":"The close check path in performWorkspaceCloseCheck completes: workspace.sessions.size === 0, workspace.close resolves without throwing, and LOGGING_ENABLED is true.","commonSituations":"Operator logs showing workspace shutdown during maintenance or idle cleanup; clients attempting to reconnect to a workspace that was just torn down; server load reduction closing unused workspaces.","solutions":["No action needed - this is a success-path log confirming cleanup.","If clients still need the workspace, reconnect before it idles out or keep a session open.","Verify clients handle workspace-down events (from workspaceProducer) by reattaching/reopening the workspace.","If workspace.close throws, check the catch block (Analytics.handleError) to see the underlying failure."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// After seeing 'Closed workspace', confirm the workspace is gone before reusing the reference\nif (!manager.hasWorkspace(uuid)) {\n  await reopenWorkspace(uuid)\n}\n","typeGuard":"function workspaceExists (workspaces: Map<string, unknown>, uuid: string): boolean {\n  return workspaces.has(uuid)\n}\n","tryCatchPattern":null,"preventionTips":["Handle workspaceEvents.down() on the consumer side to reattach clients.","Reconnect with backoff after workspace down events.","Avoid caching workspace references across idle shutdowns."],"tags":["workspace","lifecycle","session-management","logging"],"backgroundTag":"workspace-closed-no-sessions","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}