hcengineering/platform · error · ApiError

Couldn't find workspace with the provided token

Error message

Couldn't find workspace with the provided token

What it means

handleRequest authenticates the caller by resolving the token with the account service's getLoginInfoByToken. Even when a token is present, the returned login info must be a workspace login (validated by isWorkspaceLoginInfo). If the token belongs to a non-workspace principal (e.g. a regular user/account token or service token) or the info is incomplete, the handler throws ApiError(401, "Couldn't find workspace with the provided token").

Source

Thrown at services/print/pod-print/src/server.ts:125

type AsyncRequestHandler = (
  req: Request,
  res: Response,
  wsIds: WorkspaceIds,
  wsLoginInfo: WorkspaceLoginInfo,
  next: NextFunction
) => Promise<void>

const handleRequest = async (
  fn: AsyncRequestHandler,
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> => {
  try {
    const token = extractToken(req.headers, req.query)
    const wsLoginInfo = await getAccountClient(token).getLoginInfoByToken()
    if (!isWorkspaceLoginInfo(wsLoginInfo)) {
      throw new ApiError(401, "Couldn't find workspace with the provided token")
    }
    const wsIds = {
      uuid: wsLoginInfo.workspace,
      dataId: wsLoginInfo.workspaceDataId,
      url: wsLoginInfo.workspaceUrl
    }
    await fn(req, res, wsIds, wsLoginInfo, next)
  } catch (err: unknown) {
    next(err)
  }
}

const wrapRequest = (fn: AsyncRequestHandler) => (req: Request, res: Response, next: NextFunction) => {
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
  handleRequest(fn, req, res, next)
}

function parsePrintOptions (query: Request['query']): PrintOptions {

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Obtain a workspace-scoped token (workspace login info) for the target workspace and use it in the Authorization header/query/cookie
  2. Verify the token was issued by the same accounts instance the print service is configured against (config.AccountsUrl)
  3. Check that the workspace still exists and is active; re-login to refresh the token
  4. Log/inspect getLoginInfoByToken output to confirm which field is missing (workspace, workspaceDataId, workspaceUrl)

Example fix

// before
const token = userAccountToken // user token, not workspace token
const wsLoginInfo = await getAccountClient(token).getLoginInfoByToken() // not a WorkspaceLoginInfo
// after
const token = await obtainWorkspaceToken(workspaceUrl) // workspace-scoped token
const wsLoginInfo = await getAccountClient(token).getLoginInfoByToken()
if (!isWorkspaceLoginInfo(wsLoginInfo)) throw new ApiError(401, 'Token is not workspace-scoped')
Defensive patterns

Strategy: validation

Validate before calling

// confirm the token resolves to workspace login info before calling print endpoints
const info = await getAccountClient(token).getLoginInfoByToken()
if (!isWorkspaceLoginInfo(info)) {
  throw new Error('Current token is not workspace-scoped; obtain a workspace token for the print service')
}

Type guard

function isWorkspaceLoginInfo(x: unknown): x is WorkspaceLoginInfo {
  return x != null && typeof x === 'object' &&
    typeof (x as any).workspace === 'string' &&
    typeof (x as any).workspaceDataId === 'string' &&
    typeof (x as any).workspaceUrl === 'string'
}

Try / catch

try {
  const res = await fetch(printUrl, { headers: { Authorization: `Bearer ${workspaceToken}` } })
  if (res.status === 401) {
    // token is valid auth but not workspace-scoped, or workspace gone — re-acquire a workspace token
    workspaceToken = await acquireWorkspaceToken(currentWorkspace)
    return fetch(printUrl, { headers: { Authorization: `Bearer ${workspaceToken}` } })
  }
  return res
} catch (err) {
  throw new Error(`Print request failed: ${(err as Error).message}`)
}

Prevention

When it happens

Trigger: Calling a print endpoint with a valid but non-workspace token (user login token instead of a workspace token); a token for a deleted/archived workspace so getLoginInfoByToken returns info without workspace fields; a service token with no workspace attached.

Common situations: Using a personal account JWT instead of the workspace-scoped token the print service requires; workspace removed or renamed after the token was issued; copying a token from the wrong environment (dev token against prod account service); token signed for a different AccountsUrl instance.

Related errors


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