hcengineering/platform · warning

'data' is missing

Error message

'data' is missing

What it means

The /push endpoint receives Google Pub/Sub push notifications for Gmail events. The Pub/Sub envelope wraps the payload in body.message.data (base64). If that field is absent, the endpoint rejects the request with 400 and this fixed message — it is a payload-shape validation, not an exception.

Source

Thrown at services/gmail/pod-gmail/src/main.ts:161

          const { account, workspace } = decodeToken(token)

          await gmailController.signout(workspace, account)
        } catch (err) {
          ctx.error('signout error', { message: JSON.stringify(err) })
        }

        res.send()
      }
    },
    {
      endpoint: '/push',
      type: 'post',
      handler: async (req, res) => {
        try {
          const data = req.body?.message?.data
          if (data === undefined) {
            res.status(400).send({ err: "'data' is missing" })
            return
          }
          gmailController.push(data)

          res.send()
        } catch (err: any) {
          ctx.error('Push request failed', { message: err.message })
          res.status(500).send()
        }
      }
    },
    {
      endpoint: '/state',
      type: 'get',
      handler: async (req, res) => {
        try {
          const token = extractToken(req.headers)

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Send the full Google Pub/Sub push envelope: { "message": { "data": "<base64>", ... } }.
  2. Base64-encode the Gmail notification payload before publishing to the topic.
  3. Verify the Pub/Sub subscription is a push subscription with the default JSON envelope format.

Example fix

// before
{ "data": "<base64>" }
// after
{ "message": { "data": "<base64>", "messageId": "...", "publishTime": "..." } }
Defensive patterns

Strategy: validation

Validate before calling

function isPubsubPushEnvelope(body: any): body is { message: { data: string } } {
  return body != null && typeof body === 'object' &&
    body.message != null && typeof body.message.data === 'string' && body.message.data.length > 0
}
// reject early: if (!isPubsubPushEnvelope(req.body)) return res.status(400)…

Type guard

function isPubsubPushEnvelope(v: unknown): v is { message: { data: string } } {
  return typeof v === 'object' && v !== null &&
    'message' in v && typeof (v as any).message?.data === 'string'
}

Try / catch

try {
  const res = await fetch(pushUrl, { method: 'POST', body: JSON.stringify(envelope) })
  if (res.status === 400) {
    const body = await res.json()
    if (body?.err === "'data' is missing") {
      // wrap payload in the Pub/Sub push envelope and retry
    }
  }
} catch (e) { /* network error handling */ }

Prevention

When it happens

Trigger: POST to /push whose JSON body lacks body.message.data — e.g. a plain-text ping, a Pub/Sub 'pull'-style message posted incorrectly, or a non-Pub/Sub client calling the endpoint.

Common situations: Manually testing the endpoint with curl/Postman and sending the inner payload directly instead of the Pub/Sub push envelope; configuring a Pub/Sub subscription with the wrong push format (non-JSON wrapper); a load balancer rewriting the body.

Related errors


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