{"record":{"id":"a854efc095772ae9","repo":"hcengineering/platform","slug":"couldn-t-find-workspace-with-the-provided-token-a854ef","errorCode":null,"errorMessage":"Couldn't find workspace with the provided token","messagePattern":"Couldn't find workspace with the provided token","errorType":"http","errorClass":"ApiError","httpStatus":401,"severity":"error","filePath":"services/print/pod-print/src/server.ts","lineNumber":125,"sourceCode":"type AsyncRequestHandler = (\n  req: Request,\n  res: Response,\n  wsIds: WorkspaceIds,\n  wsLoginInfo: WorkspaceLoginInfo,\n  next: NextFunction\n) => Promise<void>\n\nconst handleRequest = async (\n  fn: AsyncRequestHandler,\n  req: Request,\n  res: Response,\n  next: NextFunction\n): Promise<void> => {\n  try {\n    const token = extractToken(req.headers, req.query)\n    const wsLoginInfo = await getAccountClient(token).getLoginInfoByToken()\n    if (!isWorkspaceLoginInfo(wsLoginInfo)) {\n      throw new ApiError(401, \"Couldn't find workspace with the provided token\")\n    }\n    const wsIds = {\n      uuid: wsLoginInfo.workspace,\n      dataId: wsLoginInfo.workspaceDataId,\n      url: wsLoginInfo.workspaceUrl\n    }\n    await fn(req, res, wsIds, wsLoginInfo, next)\n  } catch (err: unknown) {\n    next(err)\n  }\n}\n\nconst wrapRequest = (fn: AsyncRequestHandler) => (req: Request, res: Response, next: NextFunction) => {\n  // eslint-disable-next-line @typescript-eslint/no-floating-promises\n  handleRequest(fn, req, res, next)\n}\n\nfunction parsePrintOptions (query: Request['query']): PrintOptions {","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/print/pod-print/src/server.ts#L107-L143","documentation":"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\").","triggerScenarios":"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.","commonSituations":"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.","solutions":["Obtain a workspace-scoped token (workspace login info) for the target workspace and use it in the Authorization header/query/cookie","Verify the token was issued by the same accounts instance the print service is configured against (config.AccountsUrl)","Check that the workspace still exists and is active; re-login to refresh the token","Log/inspect getLoginInfoByToken output to confirm which field is missing (workspace, workspaceDataId, workspaceUrl)"],"exampleFix":"// before\nconst token = userAccountToken // user token, not workspace token\nconst wsLoginInfo = await getAccountClient(token).getLoginInfoByToken() // not a WorkspaceLoginInfo\n// after\nconst token = await obtainWorkspaceToken(workspaceUrl) // workspace-scoped token\nconst wsLoginInfo = await getAccountClient(token).getLoginInfoByToken()\nif (!isWorkspaceLoginInfo(wsLoginInfo)) throw new ApiError(401, 'Token is not workspace-scoped')","handlingStrategy":"validation","validationCode":"// confirm the token resolves to workspace login info before calling print endpoints\nconst info = await getAccountClient(token).getLoginInfoByToken()\nif (!isWorkspaceLoginInfo(info)) {\n  throw new Error('Current token is not workspace-scoped; obtain a workspace token for the print service')\n}","typeGuard":"function isWorkspaceLoginInfo(x: unknown): x is WorkspaceLoginInfo {\n  return x != null && typeof x === 'object' &&\n    typeof (x as any).workspace === 'string' &&\n    typeof (x as any).workspaceDataId === 'string' &&\n    typeof (x as any).workspaceUrl === 'string'\n}","tryCatchPattern":"try {\n  const res = await fetch(printUrl, { headers: { Authorization: `Bearer ${workspaceToken}` } })\n  if (res.status === 401) {\n    // token is valid auth but not workspace-scoped, or workspace gone — re-acquire a workspace token\n    workspaceToken = await acquireWorkspaceToken(currentWorkspace)\n    return fetch(printUrl, { headers: { Authorization: `Bearer ${workspaceToken}` } })\n  }\n  return res\n} catch (err) {\n  throw new Error(`Print request failed: ${(err as Error).message}`)\n}","preventionTips":["Use workspace-scoped tokens (not personal account tokens) for print endpoints","Ensure the print service and your token issuer point at the same AccountsUrl","Re-login after workspace deletion/rename to get a fresh valid token","Keep environment tokens separate: never use dev tokens against the production accounts service"],"tags":["auth","http-401","workspace","token-scope"],"backgroundTag":"token-workspace-mismatch","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}