{"record":{"id":"955fad3288db56ca","repo":"hcengineering/platform","slug":"subscriptions-is-missing","errorCode":null,"errorMessage":"'subscriptions' is missing","messagePattern":"'subscriptions' is missing","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"services/notification/pod-notification/src/main.ts","lineNumber":74,"sourceCode":"    return true\n  }\n\n  const endpoints: Endpoint[] = [\n    {\n      endpoint: '/web-push',\n      type: 'post',\n      handler: async (req, res) => {\n        if (!checkAuth(req, res)) {\n          return\n        }\n        const data: PushData | undefined = req.body?.data\n        if (data === undefined) {\n          res.status(400).send({ err: \"'data' is missing\" })\n          return\n        }\n        const subscriptions: PushSubscription[] | undefined = req.body?.subscriptions\n        if (subscriptions === undefined) {\n          res.status(400).send({ err: \"'subscriptions' is missing\" })\n          return\n        }\n        if (!webpushInitDone) {\n          res.json({ result: [] }).end()\n          return\n        }\n\n        const result = await sendPushToSubscription(ctx, subscriptions, data)\n        res.json({ result }).end()\n      }\n    }\n  ]\n\n  const server = listen(createServer(endpoints), config.Port, undefined, () => {\n    ctx.info('Notification service listening', { port: config.Port })\n  })\n\n  const shutdown = (): void => {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/notification/pod-notification/src/main.ts#L56-L92","documentation":"The pod-notification push handler responds HTTP 400 with { err: \"'subscriptions' is missing\" } when req.body.subscriptions is undefined. Even with valid data, the service needs the array of PushSubscription endpoints to deliver to; without it there is nothing to send, so it rejects the request. Note: if web-push was never initialized, the handler instead returns an empty result rather than this error.","triggerScenarios":"POST with body.data present but no 'subscriptions' key, subscriptions spelled differently ('subs', 'endpoints'), or subscriptions passed as a single object instead of an array.","commonSituations":"Client code updated to send data but subscription storage not wired in; sending one subscription object directly instead of wrapping it in an array; database of subscriptions empty leading code to omit the field instead of sending []; migrating from another push service with a different field name.","solutions":["Include 'subscriptions' as an array in the JSON body: {\"data\":{...},\"subscriptions\":[{\"endpoint\":..., \"keys\":{...}}]}.","If you have zero subscriptions, send an empty array rather than omitting the field.","Verify each item is a PushSubscription (with endpoint and keys.p256dh/keys.auth) matching the service's expected shape.","Fix field-name mismatches — the service reads exactly req.body.subscriptions."],"exampleFix":"// before\npost(pushUrl, { data, subscription: sub })\n// after\npost(pushUrl, { data, subscriptions: [sub] })","handlingStrategy":"validation","validationCode":"function hasSubscriptions(body: unknown): boolean {\n  const s = (body as any)?.subscriptions\n  return Array.isArray(s) && s.every(x => typeof (x as any)?.endpoint === 'string' && (x as any)?.keys?.p256dh && (x as any)?.keys?.auth)\n}\nif (!hasSubscriptions(payload)) throw new Error(\"push request requires a 'subscriptions' array of valid PushSubscription objects\")","typeGuard":"function isPushSubscription(v: unknown): v is { endpoint: string; keys: { p256dh: string; auth: string } } {\n  const s = v as any\n  return typeof s?.endpoint === 'string' && typeof s?.keys?.p256dh === 'string' && typeof s?.keys?.auth === 'string'\n}","tryCatchPattern":"const res = await fetch(pushUrl, opts)\nif (res.status === 400) {\n  const { err } = await res.json()\n  if (err?.includes(\"'subscriptions' is missing\")) throw new Error('push payload must include a subscriptions array (send [] if none)')\n}","preventionTips":["Always send subscriptions as an array, even when empty","Validate each PushSubscription (endpoint + keys.p256dh + keys.auth) before batching","Prune expired subscriptions from storage so valid arrays are maintained"],"tags":["http-400","validation","web-push","missing-field"],"backgroundTag":"missing-request-field","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}