{"record":{"id":"538d5e5d9a011d6a","repo":"hcengineering/platform","slug":"subscription-not-found","errorCode":null,"errorMessage":"Subscription not found","messagePattern":"Subscription not found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"error","filePath":"services/payment/pod-payment/src/server.ts","lineNumber":281,"sourceCode":"    withToken,\n    withOwner,\n    (req: RequestWithAuth, res: Response) => {\n      if (provider === undefined) {\n        res.status(503).json({ error: 'Payment provider is not configured' })\n        return\n      }\n\n      void handleRequest(\n        ctx,\n        'cancel-subscription',\n        async (ctx) => {\n          const subscriptionId = req.params.subscriptionId\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          let canceledSubscription: SubscriptionData | null\n\n          try {\n            // Cancel via provider using the provider's subscription ID\n            canceledSubscription = await provider.cancelSubscription(ctx, subscription.providerSubscriptionId)\n          } catch (err) {\n            ctx.error('Failed to cancel subscription at provider', { err })\n            res.status(500).json({ error: 'Failed to cancel subscription at provider' })\n            return\n          }\n\n          if (canceledSubscription === null) {\n            res.status(404).json({ error: 'Failed to cancel subscription at provider' })\n            return\n          }","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/payment/pod-payment/src/server.ts#L263-L299","documentation":"Before canceling, the endpoint looks up the subscription in the service's own database via accountClient.getSubscriptionById using the internal subscription ID from the URL path. If nothing is found (undefined or null) it returns HTTP 404. The provider is never contacted, meaning the ID does not correspond to any locally tracked subscription.","triggerScenarios":"POST /api/v1/subscriptions/:subscriptionId/cancel with a subscriptionId that is not in the local DB: typo'd ID, using the provider's subscription ID instead of the internal one, a subscription belonging to a different environment (staging vs prod DB), or a record deleted/never synced.","commonSituations":"Client cached an ID from a canceled/purged subscription; mixing up providerSubscriptionId and internal id; database migration or environment mismatch; calling cancel twice after the record was removed.","solutions":["Verify the subscriptionId is the internal subscription ID (not the provider's ID) and matches an existing record.","List the workspace's subscriptions via the account API to obtain a valid ID.","Check you are pointing at the correct environment's account service/DB (staging vs production).","If the record should exist, investigate the account service DB for missing/unsynced subscription rows and re-sync from the provider."],"exampleFix":"// before (provider ID used)\nPOST /api/v1/subscriptions/sub_1NproviderID/cancel // -> 404\n\n// after (internal ID)\nconst sub = await accountClient.listSubscriptions(workspaceUuid)[0]\nPOST /api/v1/subscriptions/${sub.id}/cancel // -> 200","handlingStrategy":"validation","validationCode":"const sub = await accountClient.getSubscriptionById(subscriptionId)\nif (sub === undefined || sub === null) {\n  throw new Error(`Subscription ${subscriptionId} not found locally; fetch a valid internal ID first`)\n}","typeGuard":"function subscriptionExists(s: SubscriptionData | undefined | null): s is SubscriptionData {\n  return s !== undefined && s !== null\n}","tryCatchPattern":"const res = await fetch(cancelUrl, opts)\nif (res.status === 404 && (await res.json()).error === 'Subscription not found') {\n  // re-list subscriptions to get a fresh internal ID; do not blindly retry\n}","preventionTips":["Always resolve IDs from a fresh list-subscriptions call, never from cache or the provider's ID.","Label fields explicitly (internal id vs providerSubscriptionId) in client models.","Pin clients to the correct environment's account service.","Avoid deleting local subscription rows immediately after cancellation; archive instead."],"tags":["http-404","payment","not-found","rest"],"backgroundTag":"resource-not-found","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}