hcengineering/platform · error

err.message

Error message

err.message

What it means

The final branch of the global error middleware: any thrown error that is NOT an ApiError becomes an HTTP 500 whose body is the raw err.message. This is the catch-all for unexpected exceptions in all pod endpoints.

Source

Thrown at services/gmail/pod-gmail/src/server.ts:57

  endpoints.forEach((endpoint) => {
    if (endpoint.type === 'get') {
      app.get(endpoint.endpoint, catchError(endpoint.handler))
    } else if (endpoint.type === 'post') {
      app.post(endpoint.endpoint, catchError(endpoint.handler))
    }
  })

  app.use((_req, res, _next) => {
    res.status(404).send({ message: 'Not found' })
  })

  app.use((err: any, _req: any, res: any, _next: any) => {
    if (err instanceof ApiError) {
      res.status(400).send({ code: err.code, message: err.message })
      return
    }

    res.status(500).send({ message: err.message })
  })

  return app
}

export function listen (e: Express, port: number, host?: string): Server {
  const cb = (): void => {
    console.log(`Gmail service has been started at ${host ?? '*'}:${port}`)
  }

  return host !== undefined ? e.listen(port, host, cb) : e.listen(port, cb)
}

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Check server logs / catchError wrapping to capture the full stack, since the response only carries message
  2. Reproduce with the same request payload and add targeted handling in the failing handler
  3. Harden handlers to validate inputs before dereferencing (e.g. req.body fields)
  4. Convert known error classes to ApiError so clients get 400s with codes instead of opaque 500s

Example fix

// before
const { workspace } = decodeToken(token)
// after
let workspace: string
try {
  ({ workspace } = decodeToken(token))
} catch (e) {
  throw new ApiError('INVALID_TOKEN', 'Token could not be decoded')
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate request shape to avoid server-side TypeErrors
if (typeof body !== 'object' || body == null) throw new Error('request body must be an object')

Type guard

function isServerError(body: unknown): body is { message: string } {
  return typeof body === 'object' && body !== null && typeof (body as any).message === 'string'
}

Try / catch

try {
  const res = await fetch(url, opts)
  if (res.status >= 500) {
    const body = await res.json().catch(() => ({}))
    // server bug or transient outage — retry with backoff, then alert
    await retryWithBackoff(() => fetch(url, opts))
  }
} catch (e) { /* escalate after retries exhausted */ }

Prevention

When it happens

Trigger: Any handler throws a plain Error/TypeError/unknown exception — null dereferences, DB driver errors, JSON parse failures, third-party API exceptions — reaching the Express error middleware.

Common situations: Unvalidated req fields causing TypeErrors, storage layer outages, dependency service errors, bugs introduced after refactors surfacing as opaque 500s.

Related errors


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