hcengineering/platform · error

'subscriptions' is missing

Error message

'subscriptions' is missing

What it means

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.

Source

Thrown at services/notification/pod-notification/src/main.ts:74

    return true
  }

  const endpoints: Endpoint[] = [
    {
      endpoint: '/web-push',
      type: 'post',
      handler: async (req, res) => {
        if (!checkAuth(req, res)) {
          return
        }
        const data: PushData | undefined = req.body?.data
        if (data === undefined) {
          res.status(400).send({ err: "'data' is missing" })
          return
        }
        const subscriptions: PushSubscription[] | undefined = req.body?.subscriptions
        if (subscriptions === undefined) {
          res.status(400).send({ err: "'subscriptions' is missing" })
          return
        }
        if (!webpushInitDone) {
          res.json({ result: [] }).end()
          return
        }

        const result = await sendPushToSubscription(ctx, subscriptions, data)
        res.json({ result }).end()
      }
    }
  ]

  const server = listen(createServer(endpoints), config.Port, undefined, () => {
    ctx.info('Notification service listening', { port: config.Port })
  })

  const shutdown = (): void => {

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Include 'subscriptions' as an array in the JSON body: {"data":{...},"subscriptions":[{"endpoint":..., "keys":{...}}]}.
  2. If you have zero subscriptions, send an empty array rather than omitting the field.
  3. Verify each item is a PushSubscription (with endpoint and keys.p256dh/keys.auth) matching the service's expected shape.
  4. Fix field-name mismatches — the service reads exactly req.body.subscriptions.

Example fix

// before
post(pushUrl, { data, subscription: sub })
// after
post(pushUrl, { data, subscriptions: [sub] })
Defensive patterns

Strategy: validation

Validate before calling

function hasSubscriptions(body: unknown): boolean {
  const s = (body as any)?.subscriptions
  return Array.isArray(s) && s.every(x => typeof (x as any)?.endpoint === 'string' && (x as any)?.keys?.p256dh && (x as any)?.keys?.auth)
}
if (!hasSubscriptions(payload)) throw new Error("push request requires a 'subscriptions' array of valid PushSubscription objects")

Type guard

function isPushSubscription(v: unknown): v is { endpoint: string; keys: { p256dh: string; auth: string } } {
  const s = v as any
  return typeof s?.endpoint === 'string' && typeof s?.keys?.p256dh === 'string' && typeof s?.keys?.auth === 'string'
}

Try / catch

const res = await fetch(pushUrl, opts)
if (res.status === 400) {
  const { err } = await res.json()
  if (err?.includes("'subscriptions' is missing")) throw new Error('push payload must include a subscriptions array (send [] if none)')
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/955fad3288db56ca. Report an issue: GitHub.