hcengineering/platform · error · PlatformError
account.status.WorkspaceNotFound
account.status.WorkspaceNotFound
Error message
WorkspaceNotFound
What it means
WorkspaceNotFound is thrown by batchAssignWorkspacePermission when decodeTokenVerbose returns workspace === null, i.e. the provided token is not bound to any workspace. The operation requires a workspace-scoped token to know which workspace's permissions to assign.
Source
Thrown at server/account/src/operations.ts:3435
return subscription
}
export async function batchAssignWorkspacePermission (
ctx: MeasureContext,
db: AccountDB,
branding: Branding | null,
token: string,
params: {
accountIds: AccountUuid[]
permission: string
}
): Promise<void> {
const { accountIds, permission } = params
const { account, workspace } = decodeTokenVerbose(ctx, token)
if (workspace === null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.WorkspaceNotFound, { workspaceUuid: workspace }))
}
const accRole = account === systemAccountUuid ? AccountRole.Owner : await db.getWorkspaceRole(account, workspace)
if (accRole == null || getRolePower(accRole) < getRolePower(AccountRole.Maintainer)) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
}
await db.batchAssignWorkspacePermission(workspace, accountIds, permission)
}
export async function batchRevokeWorkspacePermission (
ctx: MeasureContext,
db: AccountDB,
branding: Branding | null,
token: string,
params: {
accountIds: AccountUuid[]
permission: stringView on GitHub (pinned to 63e28dc964)
Solutions
- Obtain a workspace-scoped token (e.g. login with workspace selection or use selectWorkspace) before calling.
- Check that the target workspace still exists and the token was issued for it.
- Re-issue/refresh the token if it predates workspace deletion or migration.
Example fix
// before
await accountClient.batchAssignWorkspacePermission(loginToken, { accountIds, permission })
// after
const wsToken = await accountClient.selectWorkspace(loginToken, workspaceUuid)
await accountClient.batchAssignWorkspacePermission(wsToken, { accountIds, permission }) Defensive patterns
Strategy: try-catch
Validate before calling
const role = await getMyWorkspaceRole(workspaceUuid)
if (role === null || getRolePower(role) < getRolePower(AccountRole.Maintainer)) {
throw new Error('Maintainer role required to read subscription')
} Type guard
function hasMaintainerRole(role: AccountRole | null): boolean {
return role !== null && getRolePower(role) >= getRolePower(AccountRole.Maintainer)
} Try / catch
try {
const subscription = await client.fetchSubscription(token)
} catch (err) {
if (isPlatformError(err) && err.status.code === account.status.Forbidden) {
// surface 'requires Maintainer role' UI state or re-auth as admin
}
throw err
} Prevention
- Verify the caller's workspace role before making admin-scoped subscription calls.
- Keep a separate maintainer/owner token for billing operations.
- Assert the subscription's workspaceUuid matches the token's workspace before calling.
When it happens
Trigger: Calling batchAssignWorkspacePermission with a personal/account-level token that carries no workspace claim (workspace resolves to null).
Common situations: Using a login token instead of a workspace token; workspace was deleted so the token's workspace claim is gone; constructing a token manually without the workspace field; env/region mixups yielding a token from a non-workspace endpoint.
Related errors
- platform.status.WorkspaceNotFound
- Invalid workspace login info by token
- platform.status.AccountNotFound
- platform.status.BadRequest
- InternalServerError
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/17bbd772c7f20134.
Report an issue: GitHub.