{"record":{"id":"0b5f889253e73c4c","repo":"hcengineering/platform","slug":"err-message-0b5f88","errorCode":null,"errorMessage":"err.message","messagePattern":"err\\.message","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"services/mail/pod-mail-worker/src/index.ts","lineNumber":87,"sourceCode":"      }\n    })()\n  }\n\n  app.post('/mta-hook', catchError(handleMtaHook))\n\n  app.use((_req, res, _next) => {\n    res.status(404).send({ message: 'Not found' })\n  })\n\n  app.use((err: any, req: Request, res: any, _next: any) => {\n    ctx.error(err)\n    if (req.path === '/mta-hook') {\n      // Any error in the mta-hook should not prevent the mail server from handling emails\n      // At least the PayloadTooLargeError falls here before reacing our code\n      res.status(200).send({ action: 'accept' })\n      return\n    }\n    res.status(500).send({ message: err.message })\n  })\n\n  const server = app.listen(config.port, () => {\n    ctx.info('server started', {\n      ...config,\n      secret: config.secret !== undefined ? '(stripped)' : undefined,\n      hookToken: config.hookToken !== undefined ? '(stripped)' : undefined,\n      storageConfig: config.storageConfig !== undefined ? '(stripped)' : undefined\n    })\n  })\n  await MailWorker.create(ctx)\n\n  const shutdown = (): void => {\n    try {\n      MailWorker.getMailWorker()\n        .close()\n        .catch((err) => {\n          ctx.error('Failed to close MailWorker', { error: err.message })","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/mail/pod-mail-worker/src/index.ts#L69-L105","documentation":"The pod-mail-worker's Express error middleware returns 500 with { message: err.message } for any unhandled route error. For /mta-hook specifically it instead responds 200 { action: 'accept' } so the upstream mail server keeps accepting emails. Seeing this 500 means an error escaped a non-mta-hook route (or an error middleware path other than the mta-hook branch).","triggerScenarios":"An uncaught exception thrown synchronously or via next(err) in a pod-mail-worker route — e.g. body-parser PayloadTooLargeError on a non-mta-hook route, JSON parse failure, or a handler crash reaching the error middleware outside the req.path === '/mta-hook' branch.","commonSituations":"Sending an oversized payload that exceeds the body-parser limit; sending malformed JSON that the body parser rejects; a bug in a newly added worker route; proxies forwarding requests with unexpected content types.","solutions":["Read the returned err.message (and worker logs via ctx.error) to identify the underlying failure.","If it is PayloadTooLargeError, reduce the payload size or raise the body-parser limit configured in the worker.","If it is a JSON parse error, send valid JSON with Content-Type: application/json.","Fix or wrap the failing route handler with catchError so errors are handled where they occur."],"exampleFix":"// before\napp.post('/hook', async (req, res) => { throw new Error('boom') }) // becomes 500 err.message\n// after\napp.post('/hook', catchError(async (req, res) => { ... }))","handlingStrategy":"try-catch","validationCode":"// Guard payload size and JSON validity before sending\nconst serialized = JSON.stringify(payload)\nif (serialized.length > MAX_BODY_BYTES) throw new Error('payload exceeds body-parser limit')\nJSON.parse(serialized) // throws early on non-serializable/corrupt payload","typeGuard":"function isSerializableJson(v: unknown): boolean {\n  try { JSON.stringify(v); return true } catch { return false }\n}","tryCatchPattern":"try {\n  const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })\n  if (!res.ok) {\n    const { message } = await res.json()\n    throw new Error(`worker 500: ${message}`)\n  }\n} catch (e) {\n  ctx.error('mail worker request failed', { e })\n}","preventionTips":["Keep request bodies under the configured body-parser limit.","Always send valid JSON with the correct Content-Type.","Wrap new route handlers in catchError so errors don't hit the generic 500 middleware.","Check worker logs (ctx.error) for the full stack behind the returned err.message."],"tags":["http-500","express","error-middleware","payload-too-large"],"backgroundTag":"express-unhandled-error-500","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}