hcengineering/platform · error · PlatformError

account.status.WorkspaceNotFound

account.status.WorkspaceNotFound

Error message

WorkspaceNotFound

What it means

After the permission check, performWorkspaceOperation resolves the requested workspace id(s) via getWorkspacesInfoWithStatusByIds. If the resulting list is empty — i.e. none of the given ids match an existing workspace — it throws account.status.WorkspaceNotFound. It is thrown whenever zero workspaces are found, even if only some ids in a batch are unknown.

Source

Thrown at server/account/src/serviceOperations.ts:146

    workspaceId: WorkspaceUuid | WorkspaceUuid[]
    event: 'archive' | 'migrate-to' | 'unarchive' | 'delete' | 'reset-attempts'
    params: any[]
  }
): Promise<boolean> {
  const { workspaceId, event, params } = parameters
  const { extra, workspace } = decodeTokenVerbose(ctx, token)

  if (extra?.admin !== 'true') {
    if (event !== 'unarchive' || workspaceId !== workspace) {
      throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
    }
  }

  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

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Verify the workspace id exists by fetching workspace info (or listing workspaces) before performing the operation; correct any typo.
  2. If the workspace was deleted, recreate it or drop the operation — it cannot be archived/unarchived/deleted again.
  3. Confirm you are calling the account service instance/region that actually hosts the workspace.
  4. For batch calls, pre-validate all ids and remove nonexistent ones, or split into per-workspace calls so one bad id doesn't abort the batch.

Example fix

// before — blindly operating on a cached id
await client.performWorkspaceOperation(ctx, adminToken, { workspaceId: cachedId, event: 'unarchive', params: {} })
// after — verify existence first
const ws = await getWorkspacesInfoWithStatusByIds(db, [cachedId])
if (ws.length === 0) throw new WorkspaceNotFound(cachedId)
await client.performWorkspaceOperation(ctx, adminToken, { workspaceId: cachedId, event: 'unarchive', params: {} })
Defensive patterns

Strategy: validation

Validate before calling

const ids = Array.isArray(workspaceId) ? workspaceId : [workspaceId]
if (ids.length === 0) throw new Error('workspaceId required')
const found = await getWorkspacesInfoWithStatusByIds(db, ids)
if (found.length !== ids.length) {
  throw new Error(`Unknown workspace ids: ${ids.filter((id) => !found.some((w) => w.uuid === id))}`)
}

Type guard

function isWorkspaceId(value: unknown): value is string {
  return typeof value === 'string' &&
    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)
}

Try / catch

try {
  await client.performWorkspaceOperation(ctx, token, parameters)
} catch (err) {
  if (isPlatformError(err) && err.code === account.status.WorkspaceNotFound) {
    // treat as permanent: refresh workspace list from source of truth, drop stale ids
  }
  throw err
}

Prevention

When it happens

Trigger: Calling performWorkspaceOperation with a workspaceId (or an array whose resolved set returns no rows) that does not exist in the account DB: a deleted workspace, a typo'd/uuid-mangled id, a workspace from a different region/account instance, or an empty array.

Common situations: Stale UI cache referencing a workspace deleted moments ago; test fixtures using hardcoded workspace uuids from another environment (dev vs prod); an id copied with wrong casing/format; cross-cluster migration where workspaces exist in a different account service instance.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/f6c05a544af90857. Report an issue: GitHub.