hcengineering/platform · info
closing workspace, no users
Error message
closing workspace, no users
What it means
The SessionManager periodically ticks workspaces; if a workspace has zero sessions, has finished initialization, is not already closing, and its softShutdown countdown reaches zero, the manager logs this warning and starts a workspace close check (soft shutdown). This is normal garbage collection of idle workspaces, freeing memory.
Source
Thrown at foundations/server/packages/server/src/sessionManager.ts:323
for (const s of workspace.sessions) {
if (this.ticks % (5 * 60 * ticksPerSecond) === workspace.tickHash) {
s[1].session.mins5.find = s[1].session.current.find
s[1].session.mins5.tx = s[1].session.current.tx
s[1].session.current = { find: 0, tx: 0 }
}
}
// Wait some time for new client to appear before closing workspace.
if (
!workspace.maintenance &&
workspace.sessions.size === 0 &&
workspace.closing === undefined &&
workspace.workspaceInitCompleted
) {
workspace.softShutdown--
if (workspace.softShutdown <= 0) {
this.ctx.warn('closing workspace, no users', {
workspace: workspace.wsId.url,
wsId,
upgrade: workspace.maintenance
})
workspace.closing = this.performWorkspaceCloseCheck(workspace)
}
} else {
workspace.softShutdown = workspaceSoftShutdownTicks
}
}
}
private sendUserWorkspaceStats (): void {
const { sys, user, anonymous } = this.calcWorkspaceStats(Array.from(this.sessions.values()))
let userWorkspaces: number = 0
let sysOnlyWorkspaces: number = 0
View on GitHub (pinned to 63e28dc964)
Solutions
- No action needed if workspaces are simply idle — they will be re-initialized on next connect
- If workspaces close too eagerly, increase the softShutdown timeout configuration
- If users report disconnects, check why sessions drop (network, ping timeouts) so the workspace never reaches zero sessions
- Monitor for repeated close/init cycles which would indicate a reconnect loop
Example fix
// before softShutdown: 100 // ticks // after (config, slower close of idle workspaces) WORKSPACE_SOFT_SHUTDOWN_TICKS=1000
Defensive patterns
Strategy: try-catch
Validate before calling
const ws = await getWorkspace(ctx, workspaceId)
if (ws && ws.sessions.size > 0) console.log('workspace active; will not be closed by tick') Type guard
function isIdleForClose(ws: { sessions: Set<unknown>; closing?: unknown; workspaceInitCompleted: boolean }): boolean {
return ws.workspaceInitCompleted && ws.closing === undefined && ws.sessions.size === 0
} Try / catch
try {
await client.find(ctx, clazz, query, { workspaceId })
} catch (err) {
if (isWorkspaceClosedError(err)) {
await reconnectWorkspace(workspaceId) // triggers re-init
} else throw err
} Prevention
- Treat this warning as normal idle lifecycle, not a failure
- Handle 'workspace closed' errors on the client by reconnecting (workspace re-initializes automatically)
- Increase softShutdown ticks if frequent re-init cost matters
- Watch for close/init thrash indicating a client reconnect loop
When it happens
Trigger: handleWorkspaceTick (from handleTick) sees workspace.sessions.size === 0 and softShutdown decrements to <= 0 — i.e. no user has been connected for the full softShutdown interval.
Common situations: Long-lived server accumulating idle workspaces; clients disconnecting and not reconnecting; test environments leaving workspaces open; misread as an error when it's expected lifecycle behavior.
Related errors
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/d47a2a5695313549.
Report an issue: GitHub.