{"record":{"id":"304159f1be3acae6","repo":"hcengineering/platform","slug":"missing-account-cannot-update-plan","errorCode":null,"errorMessage":"Missing account, cannot update plan","messagePattern":"Missing account, cannot update plan","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"services/payment/pod-payment/src/server.ts","lineNumber":417,"sourceCode":"            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          // Get subscription from our database using internal ID\n          const subscription = await accountClient.getSubscriptionById(subscriptionId)\n\n          if (subscription === undefined || subscription === null) {\n            res.status(404).json({ error: 'Subscription not found' })\n            return\n          }\n\n          const accountUuid = subscription.accountUuid ?? req.token?.account\n          if (accountUuid == null) {\n            res.status(400).json({ error: 'Missing account, cannot update plan' })\n            return\n          }\n\n          let updateResult: SubscriptionData | CheckoutResponse | null\n\n          try {\n            // Update via provider using the provider's subscription ID\n            updateResult = await provider.updateSubscriptionPlan(\n              ctx,\n              subscription.providerSubscriptionId,\n              plan,\n              loginInfo.workspaceUrl,\n              accountUuid\n            )\n          } catch (err) {\n            ctx.error('Failed to update subscription at provider', { err })\n            res.status(500).json({ error: 'Failed to update subscription at provider' })\n            return","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/payment/pod-payment/src/server.ts#L399-L435","documentation":"HTTP 400 returned when neither subscription.accountUuid nor req.token?.account yields an account UUID (services/payment/pod-payment/src/server.ts:415-418). provider.updateSubscriptionPlan requires the accountUuid to attribute the plan change, but the stored subscription has no accountUuid and the auth token carries no account claim.","triggerScenarios":"POST .../updatePlan on a subscription row missing accountUuid (legacy/pre-migration rows, or rows created outside normal signup) AND a token whose payload has no account claim — e.g. a narrowly-scoped or malformed token.","commonSituations":"Subscriptions created before the accountUuid field existed; subscriptions synced from provider without account linkage; tokens issued by a legacy auth flow lacking the account claim; tokens for accounts deleted mid-session.","solutions":["Use a token that includes the account claim (re-login / re-mint the token) so req.token.account is populated.","Backfill subscription.accountUuid in the accounts database for the affected subscription.","Fix the signup/checkout flow so subscriptions are stored with accountUuid set.","Verify the token's account claim is correctly parsed by withToken (claim name mismatch)."],"exampleFix":"// before: legacy row with no linkage\nUPDATE subscription SET account_uuid = NULL WHERE ...  -- problem persists\n// after: backfill account linkage\nUPDATE subscription SET account_uuid = '<account-uuid>' WHERE id = '<subscription-id>';","handlingStrategy":"validation","validationCode":"const sub = await getSubscription(id)\nconst accountUuid = sub.accountUuid ?? tokenClaims.account\nif (!accountUuid) {\n  throw new DataError('No account linkage on subscription and no account claim in token; backfill or re-authenticate')\n}","typeGuard":"function hasAccount(sub: { accountUuid?: string | null }, token?: { account?: string }): sub is { accountUuid: string } {\n  return Boolean(sub.accountUuid ?? token?.account)\n}","tryCatchPattern":"try {\n  return await updatePlan(id, plan)\n} catch (err) {\n  if (err instanceof HttpError && err.status === 400 && /missing account/i.test(err.message)) {\n    const token = await reauthenticateWithAccountScope()\n    return updatePlan(id, plan, token)\n  }\n  throw err\n}","preventionTips":["Backfill accountUuid on legacy subscription rows during migrations.","Ensure the checkout flow always stores accountUuid at creation time.","Use tokens minted after account creation so the account claim exists.","Add a DB constraint/check flagging subscriptions without account linkage."],"tags":["http-400","auth","data-integrity","subscription"],"backgroundTag":"missing-account-claim","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}