{"record":{"id":"48e766041205d797","repo":"hcengineering/platform","slug":"workspace-or-account-not-found-in-token","errorCode":null,"errorMessage":"Workspace or account not found in token","messagePattern":"Workspace or account not found in token","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"foundations/core/packages/client-resources/src/index.ts","lineNumber":128,"sourceCode":"                return\n              }\n              if (tx?._class === core.class.TxWorkspaceEvent) {\n                const event = tx as TxWorkspaceEvent\n                if (event.event === WorkspaceEvent.MaintenanceNotification) {\n                  void setPlatformStatus(\n                    new Status(Severity.WARNING, platform.status.MaintenanceWarning, {\n                      time: event.params.timeMinutes,\n                      message: event.params.message ?? ''\n                    })\n                  )\n                }\n              }\n            }\n            handler(...txes)\n          }\n          const tokenPayload = decodeTokenPayload(token)\n          if (tokenPayload.workspace === undefined || tokenPayload.account === undefined) {\n            throw new Error('Workspace or account not found in token')\n          }\n\n          const newOpt = { ...opt }\n          const connectTimeout = opt?.connectionTimeout ?? getMetadata(clientPlugin.metadata.ConnectionTimeout)\n          let connectPromise: Promise<void> | undefined\n          if ((connectTimeout ?? 0) > 0) {\n            connectPromise = new Promise<void>((resolve, reject) => {\n              const connectTO = setTimeout(() => {\n                if (!clientConnection.isConnected()) {\n                  newOpt.onConnect = undefined\n                  void clientConnection?.close()\n                  void opt?.onDialTimeout?.()\n                  reject(new Error(`Connection timeout, and no connection established to ${endpoint}`))\n                }\n              }, connectTimeout)\n              newOpt.onConnect = async (event, lastTx, data) => {\n                try {\n                  await opt?.onConnect?.(event, lastTx, data)","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/core/packages/client-resources/src/index.ts#L110-L146","documentation":"During client connect setup, the token's payload is decoded and must contain both workspace and account claims. If either is missing, handler throws 'Workspace or account not found in token'. This guards against connecting with a token that is not workspace-scoped.","triggerScenarios":"Passing a token issued without workspace/account claims (e.g. a bare login token, a malformed JWT, or a token from a different auth scheme) into the client connect/handler flow.","commonSituations":"Using an account-level token instead of a workspace token; tokens issued by an older/patched auth service with a different payload shape; manually copy-pasted or truncated JWT; decoding with the wrong secret producing garbage payload.","solutions":["Obtain the token via getWorkspaceToken, which returns a workspace-scoped token with both claims.","Decode the token payload locally (decodeTokenPayload) and verify workspace/account before connecting.","Re-login to get a fresh, correctly-scoped token.","Check that the token wasn't truncated or altered (valid JWT: header.payload.signature).","Verify client and server auth library versions agree on payload field names."],"exampleFix":"// before\nawait connect(myLoginToken, ops)\n// after\nconst payload = decodeTokenPayload(myLoginToken)\nif (payload.workspace === undefined || payload.account === undefined) {\n  const wsToken = await getWorkspaceToken({ token: myLoginToken, workspace })\n  await connect(wsToken.token, ops)\n} else {\n  await connect(myLoginToken, ops)\n}","handlingStrategy":"validation","validationCode":"import { decodeTokenPayload } from '@hcengineering/client-resources'\nconst payload = decodeTokenPayload(token)\nif (payload.workspace === undefined || payload.account === undefined) {\n  token = (await getWorkspaceToken({ token, workspace })).token\n}","typeGuard":"function isWorkspaceToken(p: Record<string, unknown> | undefined): p is { workspace: string, account: string } {\n  return p !== undefined && typeof p.workspace === 'string' && typeof p.account === 'string'\n}","tryCatchPattern":"try {\n  await connect(token, ops)\n} catch (err) {\n  if (err.message.includes('Workspace or account not found in token')) {\n    const ws = await getWorkspaceToken({ token, workspace })\n    return connect(ws.token, ops)\n  }\n  throw err\n}","preventionTips":["Always obtain connect tokens via getWorkspaceToken, not raw login tokens","Decode and check claims before connecting","Validate token integrity (untruncated JWT) after copy/paste","Keep auth client versions consistent to preserve payload shapes"],"tags":["jwt","authentication","token"],"backgroundTag":"jwt-missing-claims","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}