hcengineering/platform · error · PlatformError
Delete allowed only for active workspaces
Error message
Delete allowed only for active workspaces
What it means
The 'delete' branch of performWorkspaceOperation refuses to delete workspaces that are not currently in 'active' mode. The two-step deletion design marks active workspaces as 'pending-deletion' and a background worker finishes the actual removal; deleting a workspace already in another lifecycle mode (e.g. archiving, archived, pending-deletion) is rejected with unknownError('Delete allowed only for active workspaces').
Source
Thrown at server/account/src/serviceOperations.ts:159
const workspaceUuids = Array.isArray(workspaceId) ? workspaceId : [workspaceId]
const workspaces = await getWorkspacesInfoWithStatusByIds(db, workspaceUuids)
if (workspaces.length === 0) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.WorkspaceNotFound, {}))
}
let ops = 0
for (const workspace of workspaces) {
const update: Partial<WorkspaceStatus> = {}
switch (event) {
case 'reset-attempts':
update.processingAttempts = 0
update.lastProcessingTime = Date.now() - processingTimeoutMs // To not wait for next step
break
case 'delete':
if (workspace.status.mode !== 'active') {
throw new PlatformError(unknownError('Delete allowed only for active workspaces'))
}
update.mode = 'pending-deletion'
update.processingAttempts = 0
update.processingProgress = 0
update.lastProcessingTime = Date.now() - processingTimeoutMs // To not wait for next step
break
case 'archive':
if (!isActiveMode(workspace.status.mode)) {
throw new PlatformError(unknownError('Archiving allowed only for active workspaces'))
}
update.mode = 'archiving-pending-backup'
update.processingAttempts = 0
update.processingProgress = 0
update.lastProcessingTime = Date.now() - processingTimeoutMs // To not wait for next step
break
case 'unarchive':View on GitHub (pinned to 63e28dc964)
Solutions
- Check workspace.status.mode before deleting; only issue event='delete' when mode === 'active'.
- If the workspace is already 'pending-deletion', do nothing — the background processor will complete the deletion.
- For archived workspaces, first run event='unarchive' to return it to active, then issue the delete.
- If the workspace is stuck in a transitional mode (e.g. archiving-pending-backup) due to a failed job, investigate/repair the processing state or reset processingAttempts via 'reset-attempts' before retrying.
Example fix
// before — delete regardless of mode
await client.performWorkspaceOperation(ctx, adminToken, { workspaceId: wsId, event: 'delete', params: {} })
// after — guard on mode
const [ws] = await getWorkspaceInfo(ctx, adminToken, wsId)
if (ws.status.mode !== 'active') {
if (ws.status.mode === 'pending-deletion') return // already deleting
await client.performWorkspaceOperation(ctx, adminToken, { workspaceId: wsId, event: 'unarchive', params: {} })
}
await client.performWorkspaceOperation(ctx, adminToken, { workspaceId: wsId, event: 'delete', params: {} }) Defensive patterns
Strategy: validation
Validate before calling
const [ws] = await getWorkspacesInfoWithStatusByIds(db, [workspaceId])
if (ws?.status.mode !== 'active') {
throw new Error(`Cannot delete workspace in mode '${ws?.status.mode}'; only active workspaces can be deleted`)
} Type guard
function isDeletable(ws: { status: { mode: string } } | undefined): ws is { status: { mode: 'active' } } {
return ws !== undefined && ws.status.mode === 'active'
} Try / catch
try {
await client.performWorkspaceOperation(ctx, token, { workspaceId, event: 'delete', params: {} })
} catch (err) {
if (String(err?.message).includes('Delete allowed only for active workspaces')) {
// re-fetch status; skip if pending-deletion, unarchive first if archived
return
}
throw err
} Prevention
- Always fetch fresh workspace status immediately before lifecycle operations.
- Treat delete as idempotent: ignore workspaces already in 'pending-deletion'.
- Disable delete buttons in UI unless the displayed mode is 'active'.
- Serialize lifecycle operations per workspace (locking/queue) to avoid racing transitions.
When it happens
Trigger: Calling performWorkspaceOperation with event='delete' (with admin or matching-workspace permission) on a workspace whose status.mode is anything other than 'active' — e.g. the workspace is archived, already pending-deletion, mid-archive/restore, or suspended.
Common situations: Double-clicking a delete button so the second request hits a workspace already in 'pending-deletion'; running a cleanup script over all workspaces including archived ones; deleting a workspace that was just archived by another admin; a workspace stuck in an intermediate mode (archiving-pending-backup) after a failed backup job.
Related errors
- Archiving allowed only for active workspaces
- Cannot start recording from state: ${state}
- Cannot stop from state: ${state}
- Cannot pause from state: ${state}
- Cannot resume from state: ${state}
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/6a7a26462e3611d9.
Report an issue: GitHub.