hcengineering/platform · error
Workspace is closing
Error message
Workspace is closing
What it means
TSessionManager tracks workspaces and their closing state. When handling a request it looks up the workspace by uuid and refuses to serve if the workspace is missing or is in the middle of closing (workspace.closing !== undefined), throwing 'Workspace is closing' so requests are not processed against a shutting-down workspace.
Source
Thrown at foundations/server/packages/server/src/sessionManager.ts:1557
ws: ConnectionSocket,
operation: (ctx: ClientSessionCtx, rateLimit: RateLimitInfo | undefined) => Promise<void>
): Promise<RateLimitInfo | undefined> {
const rateLimitStatus = this.checkRate(service)
// If remaining is 0, rate limit is exceeded
if (rateLimitStatus?.remaining === 0) {
return await Promise.resolve(rateLimitStatus)
}
const source = service.token.extra?.service ?? '🤦♂️user'
// Calculate total number of clients
const reqId = generateId()
const st = Date.now()
try {
const workspace = this.workspaces.get(service.workspace.uuid)
if (workspace === undefined || workspace.closing !== undefined) {
throw new Error('Workspace is closing')
}
service.requests.set(reqId, {
id: reqId,
params: {},
start: st
})
try {
await this.counters.withCounter('request', 1, () =>
workspace.with(async (pipeline) => {
await requestCtx.with(
'🧨 ' + method,
{ source, mode: 'rpc' },
(callTx) =>
operation(
this.createOpContext(callTx, requestCtx, pipeline, reqId, service, ws, rateLimitStatus),
rateLimitStatusView on GitHub (pinned to 63e28dc964)
Solutions
- Retry the request after the workspace finishes closing/restarting
- Check workspace availability (or wait for a 'ready' signal) before sending requests
- Re-open/reconnect the workspace if it was permanently closed
- Handle this error client-side as a transient shutdown signal and back off
Example fix
// before
await sendRequest(service, params)
// after
try {
await sendRequest(service, params)
} catch (e) {
if (e.message === 'Workspace is closing') {
await waitForWorkspaceReady(service.workspace.uuid)
await sendRequest(service, params)
} else throw e
} Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
async function sendWithRetry(fn, { retries = 3, baseMs = 500 } = {}) {
for (let i = 0; ; i++) {
try {
return await fn()
} catch (e) {
if (e.message === 'Workspace is closing' && i < retries) {
await new Promise(r => setTimeout(r, baseMs * 2 ** i))
continue
}
throw e
}
}
} Prevention
- Track workspace lifecycle state client-side and pause sends while a close/restart is in flight
- Subscribe to workspace availability events instead of polling blind
- Use exponential backoff on this specific error; it is transient during shutdowns
- During maintenance, drain clients before closing workspaces
When it happens
Trigger: Sending a request (with a freshly generated reqId) to a workspace that is currently shutting down, or to a workspace uuid that no longer exists in the manager's map.
Common situations: Client requests racing server shutdown/workspace close; request sent right after workspace was closed or migrated; reconnect attempts during maintenance windows.
Related errors
- closing workspace, no users
- Clients disconnected. Closing Workspace...
- Workspace closed...
- Workspace ${options.workspace} not found
- Workspace not found
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/b4418ccce1d9a78d.
Report an issue: GitHub.