hcengineering/platform · error · ApiError

Target workspace not found or not accessible

Error message

Target workspace not found or not accessible

What it means

The pod-export server looks up the target workspace by ID in the caller's workspace login info returned by the accounts service. This HTTP 404 error means `targetWsLoginInfo.workspaces[targetWorkspace]` was undefined — the authenticated user has no membership/visibility of that workspace, so export cannot proceed.

Solutions

  1. Verify the target workspace UUID and that it still exists in the target environment.
  2. Ensure the user behind the token is a member of the target workspace (accept the invite / add the account).
  3. Call the accounts service getLoginWithWorkspaceInfo yourself and pick the ID from the returned workspaces map.
  4. Check you are not mixing workspace IDs across environments/dev vs prod.

Example fix

// before
targetWorkspace = '1234abcd-old-id'
// after
const info = await accountClient.getLoginWithWorkspaceInfo()
targetWorkspace = Object.keys(info.workspaces).find(w => info.workspaces[w].url === 'target-ws-url')
Defensive patterns

Strategy: validation

Validate before calling

const info = await accountClient.getLoginWithWorkspaceInfo()
if (!(targetWorkspace in info.workspaces)) {
  throw new Error(`Workspace ${targetWorkspace} not accessible to this account; available: ${Object.keys(info.workspaces).join(', ')}`)
}

Type guard

function isAccessibleWorkspace(info: LoginWithWorkspaceInfo, wsId: string): boolean {
  return info.workspaces[wsId] !== undefined
}

Try / catch

try {
  await exportPod({ targetWorkspace })
} catch (err) {
  if (err instanceof ApiError && err.status === 404 && /Target workspace/.test(err.message)) {
    const info = await accountClient.getLoginWithWorkspaceInfo()
    console.error(`Use one of: ${Object.keys(info.workspaces).join(', ')}`)
  } else throw err
}

Prevention

When it happens

Trigger: Passing a targetWorkspace (workspace UUID) that does not exist, was deleted, or that the token's account is not a member of; calling getLoginWithWorkspaceInfo and finding no matching key in the workspaces map.

Common situations: Stale workspace IDs from old configs after a workspace was removed; typos in the UUID; exporting with a user account that was never invited to the destination workspace; environment mismatch (pointing at a workspace ID from another environment).

Related errors


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

Appendix: source

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

        }
        if (includeAttachments !== undefined && typeof includeAttachments !== 'boolean') {
          measureCtx.warn(`Invalid includeAttachments: ${String(includeAttachments)}`)
          throw new ApiError(400, 'Invalid includeAttachments. Must be boolean')
        }

        decodedToken = decodeToken(token)
        if (decodedToken.extra?.readonly !== undefined) {
          throw new ApiError(403, 'Forbidden: read-only token')
        }

        // Get target workspace info
        const accountClient = getClient(envConfig.AccountsUrl, token)
        const targetWsLoginInfo = await accountClient.getLoginWithWorkspaceInfo()

        const targetWsInfo = targetWsLoginInfo.workspaces[targetWorkspace]
        if (targetWsInfo === undefined) {
          measureCtx.warn(`Target workspace not found or not accessible: ${targetWorkspace}`)
          throw new ApiError(404, 'Target workspace not found or not accessible')
        }

        // Verify user has write access to target workspace
        const isAdmin: boolean = decodedToken.extra?.admin === 'true'
        if (!isAdmin && targetWsInfo.role !== AccountRole.Owner) {
          measureCtx.warn(
            `User does not have write access to target workspace: ${targetWorkspace}, role: ${targetWsInfo.role}`
          )
          throw new ApiError(403, 'You do not have write access to the target workspace. Owner role required.')
        }

        const targetWsIds: WorkspaceIds = {
          uuid: targetWorkspace,
          dataId: targetWsInfo.dataId,
          url: targetWsInfo.url
        }

        const targetToken = generateToken(decodedToken.account, targetWorkspace, {

View on GitHub (pinned to 63e28dc964)