hcengineering/platform · error

err.message (fallback: 'Internal Server Error')

Error message

err.message (fallback: 'Internal Server Error')

What it means

The global Express error middleware logs the error, reports it to Analytics (unless its message is in the ignore list), and responds 500 with a JSON body whose message is err.message when non-empty, otherwise 'Internal Server Error'. It handles errors from middleware/routes other than the backup handler, e.g. JSON body parsing failures or ApiError thrown elsewhere.

Source

Thrown at services/backup/backup-api-pod/src/server.ts:390

      'File too large' // happens when the file exceeds the limit set by express-fileupload
    ]

    return !ignoreMessages.includes(err.message)
  }

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

    // do not send some errors to analytics
    if (sendErrorToAnalytics(err)) {
      Analytics.handleError(err)
    }

    res.status(500).json({ message: err.message?.length > 0 ? err.message : 'Internal Server Error' })
  })

  app.get('/api/v1/statistics', (req, res) => {
    try {
      const token = req.query.token as string
      const payload = decodeToken(token)
      const admin = payload.extra?.admin === 'true'
      res.setHeader('Content-Type', 'application/json')
      res.setHeader('Connection', 'keep-alive')
      res.setHeader('Keep-Alive', 'timeout=5')
      res.setHeader('Cache-Control', cacheControlNoCache)

      const json = JSON.stringify({
        metrics: metricsAggregate((ctx as any).metrics),
        statistics: {
          cpu: getCPUInfo(),
          memory: getMemoryInfo()
        },

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Read the JSON body's message field — it contains the original err.message with the root cause
  2. Fix the request payload (valid JSON, within the 50mb body limit)
  3. Check server logs/Analytics for the full stack trace of the reported error
  4. If the message leaks internals, wrap known failures in ApiError with a proper code

Example fix

// before
res.status(500).json({ message: err.message?.length > 0 ? err.message : 'Internal Server Error' })
// after
const msg = err instanceof ApiError ? err.message : 'Internal Server Error'
res.status(500).json({ message: msg })
Defensive patterns

Strategy: try-catch

Validate before calling

// send only valid, reasonably sized JSON bodies
JSON.parse(payload) // throws early client-side on malformed JSON
if (payload.length > 50 * 1024 * 1024) throw new Error('Body exceeds 50mb limit')

Type guard

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

Try / catch

const res = await fetch(url, options)
if (res.status === 500) {
  const body = await res.json().catch(() => ({ message: 'Internal Server Error' }))
  throw new Error(body.message)
}

Prevention

When it happens

Trigger: Malformed JSON in a request body exceeding or failing express.json parsing, thrown ApiError instances with codes, or any uncaught synchronous error in middleware (excluding the handled /api/backup route).

Common situations: Clients posting invalid JSON to endpoints on this service, oversized payloads beyond the 50mb limit, or unexpected bugs in middleware surfacing as 500 with the raw error message.

Understand the failure class

Related errors


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