hcengineering/platform · error

Not an owner of workspace

Error message

Not an owner of workspace

What it means

Same export route's role check: when the token's workspace exists in the accounts service but the caller's role in that workspace is not AccountRole.Owner and the token is not an admin token, the route responds 401 'Not an owner of workspace'. Exporting into another workspace is restricted to owners.

Source

Thrown at services/export/pod-export/src/server.ts:326

      const decodedToken = decodeToken(token)
      if (decodedToken.extra?.readonly !== undefined) {
        throw new ApiError(403, 'Forbidden')
      }
      const isAdmin: boolean = decodedToken.extra?.admin === 'true'

      const accountClient = getClient(envConfig.AccountsUrl, token)

      try {
        const info = await accountClient.getLoginWithWorkspaceInfo()
        const winfo = info.workspaces[decodedToken.workspace]
        if (!isAdmin) {
          if (winfo === undefined) {
            res.status(401).end('Invalid workspace')
            return
          } else {
            if (winfo.role !== AccountRole.Owner) {
              res.status(401).end('Not an owner of workspace')
              return
            }
          }
        }
      } catch (err: any) {
        res.status(401).end('Invalid workspace')
        return
      }

      const sysToken = generateToken(systemAccountUuid, decodedToken.workspace, {
        service: 'export'
      })

      const platformClient = await createPlatformClient(sysToken)
      const account = decodedToken.account

      const txOperations = new TxOperations(platformClient, socialId)

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Ask a workspace Owner (or an admin token) to perform the export.
  2. Have an existing owner elevate the account's role to Owner in the workspace settings.
  3. Confirm the role server-side; a cached account role can lag after promotion — re-login for a fresh token.
  4. If this is an automated job, provision a dedicated owner/service account for it.

Example fix

// before (member token)
await exportApi.export(memberToken, targetWs)
// after (owner token)
const ownerLogin = await loginAs(ownerAccount)
await exportApi.export(ownerLogin.token, targetWs)
Defensive patterns

Strategy: validation

Validate before calling

// verify role before calling export
const info = await accountClient.getLoginWithWorkspaceInfo()
const winfo = info.workspaces[targetWorkspace]
if (winfo && winfo.role !== 'Owner') {
  throw new Error('export requires Owner role in the target workspace')
}

Type guard

function isOwner(winfo: { role: string } | undefined): boolean {
  return winfo?.role === 'Owner'
}

Try / catch

const res = await exportApi.exportToWorkspace(token, payload)
if (res.status === 401 && (await res.text()) === 'Not an owner of workspace') {
  throw new Error('current account is not an Owner — request elevation or use an owner token')
}

Prevention

When it happens

Trigger: POST to the export-to-workspace route with a valid, non-admin token whose workspace role (info.workspaces[decodedToken.workspace].role) is Member/Guest/etc. rather than Owner.

Common situations: A regular member trying to import/export data into a team workspace, service integrations using a non-owner account's token, or role downgrades after the token was issued.

Related errors


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