hcengineering/platform · error

Missing workspace role

Error message

Missing workspace role

What it means

withOwnerAsync rejects with 401 'Missing workspace role' when the resolved loginInfo lacks a 'role' property — the account service returned login info that is not workspace-scoped (e.g. global/system login info instead of a workspace membership record).

Solutions

  1. Add the user to the target workspace with an assigned role in the account service
  2. Verify the account service version returns workspace-scoped login info including 'role' (check for API drift)
  3. Ensure the token/workspace used to fetch login info is the same workspace the route targets
  4. Check that account service data migrations completed for this workspace
Defensive patterns

Strategy: validation

Validate before calling

// verify workspace membership/role before calling owner-guarded routes
const loginInfo = await accountClient.getLoginInfoByToken()
if (loginInfo == null || !('role' in loginInfo)) {
  throw new Error('No workspace role: join the workspace before calling this API')
}

Type guard

function hasWorkspaceRole(info: unknown): info is { role: AccountRole } {
  return typeof info === 'object' && info != null && 'role' in info
}

Try / catch

try {
  const res = await callWorkspaceApi()
} catch (err) {
  if (err.response?.status === 401 && err.response.data?.message === 'Missing workspace role') {
    // direct user to join the workspace / check account service membership data
  }
}

Prevention

When it happens

Trigger: A non-admin caller whose getLoginInfoByToken() result has no 'role' field, meaning they have no workspace-scoped membership record for the token's workspace, or the account client fetched the wrong kind of login info.

Common situations: User authenticated globally but never added to the workspace; account service version returning a shape without role (API change); requesting login info for the wrong workspace context; data migration leaving workspace memberships incomplete.

Related errors


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

Appendix: source

Thrown at services/payment/pod-payment/src/middleware.ts:91

const withOwnerAsync = async (req: RequestWithAuth, res: Response, next: NextFunction): Promise<void> => {
  if (req.token === undefined || req.token == null) {
    res.status(401).json({ message: 'Token error' }).end()
    return
  }
  if (req.params.workspace != null && req.token.workspace !== req.params.workspace) {
    res.status(401).json({ message: 'Workspace mismatch' }).end()
    return
  }
  if (req.token.account !== systemAccountUuid && req.token.extra?.admin !== 'true') {
    const accountClient = getAccountClient(req.headers.authorization?.split(' ')[1])
    const loginInfo = req.loginInfo ?? (await accountClient.getLoginInfoByToken())
    if (loginInfo == null) {
      res.status(403).json({ message: 'Missing auth info' }).end()
      return
    }
    if (!('role' in loginInfo)) {
      res.status(401).json({ message: 'Missing workspace role' }).end()
      return
    }
    if (loginInfo.role !== AccountRole.Owner) {
      res.status(401).json({ message: 'Workspace owners only' }).end()
      return
    }
  }

  next()
}

View on GitHub (pinned to 63e28dc964)