{"record":{"id":"f89ea4829af0266c","repo":"hcengineering/platform","slug":"missing-workspace-in-token","errorCode":null,"errorMessage":"Missing workspace in token","messagePattern":"Missing workspace in token","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"services/payment/pod-payment/src/server.ts","lineNumber":217,"sourceCode":"        return\n      }\n\n      void handleRequest(\n        ctx,\n        'create-subscription',\n        async (ctx) => {\n          const workspaceUuid = req.token?.workspace\n          const accountUuid = req.token?.account\n          const request = req.body as SubscribeRequest\n          const loginInfo = req.loginInfo as WorkspaceLoginInfo\n\n          if (accountUuid === undefined) {\n            res.status(401).json({ error: 'Missing account in token' })\n            return\n          }\n\n          if (workspaceUuid === undefined) {\n            res.status(401).json({ error: 'Missing workspace in token' })\n            return\n          }\n\n          if (loginInfo?.workspaceUrl === undefined) {\n            res.status(401).json({ error: 'Missing workspace url in login info' })\n            return\n          }\n\n          if (request.type === undefined || request.plan === undefined) {\n            res.status(400).json({ error: 'Missing required fields: type, plan' })\n            return\n          }\n\n          let createSubResponse: CheckoutResponse\n\n          try {\n            createSubResponse = await provider.createSubscription(\n              ctx,","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/payment/pod-payment/src/server.ts#L199-L235","documentation":"The create-subscription route requires the token's workspace claim. If req.token.workspace is undefined after the account check passes, the request is rejected with 401 'Missing workspace in token', since subscriptions are created per workspace.","triggerScenarios":"Token issued without a workspace claim; user token from an auth flow that doesn't scope to a workspace; request hitting the subscription endpoint before workspace selection in the client; claim name mismatch between issuer and middleware.","commonSituations":"Client calling subscription APIs on a bare account token; multi-tenant apps where the login flow skips workspace context; older tokens minted before workspace claims existed.","solutions":["Obtain a token scoped to a workspace (complete workspace selection/login flow) and retry","Ensure the auth service includes workspace in the token payload","Verify middleware maps the correct claim into req.token.workspace","Check client state sends the workspace-scoped token, not the account-only one"],"exampleFix":"// before\nconst token = await auth.login(email) // no workspace scope\n// after\nconst token = await auth.loginToWorkspace(workspaceId, email)","handlingStrategy":"validation","validationCode":"const payload = decodeJwt(token)\nif (payload.workspace === undefined) {\n  throw new Error('Token is missing the workspace claim; log in to a workspace first')\n}","typeGuard":"function tokenHasWorkspace(token: { workspace?: string } | undefined): token is { workspace: string } {\n  return typeof token?.workspace === 'string' && token.workspace.length > 0\n}","tryCatchPattern":null,"preventionTips":["Complete the workspace-selection login flow before calling subscription APIs","Include workspace in tokens issued for multi-tenant operations","Keep claim names consistent between auth issuer and middleware","Check client token state before payment calls"],"tags":["auth","jwt","http-401","token","multi-tenancy"],"backgroundTag":"missing-token-claim","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}