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
- Read the JSON body's message field — it contains the original err.message with the root cause
- Fix the request payload (valid JSON, within the 50mb body limit)
- Check server logs/Analytics for the full stack trace of the reported error
- 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
- Validate JSON payloads before posting
- Keep request bodies under the 50mb express.json limit
- Use ApiError with proper codes so clients get structured errors
- Monitor Analytics for recurring 500 messages
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
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/8c8a5b8610bcde11.
Report an issue: GitHub.