{"record":{"id":"adba73a2fa140114","repo":"hcengineering/platform","slug":"err-message-length-0-err-message-internal","errorCode":null,"errorMessage":"err.message?.length > 0 ? err.message : 'Internal Server Error'","messagePattern":"err\\.message\\?\\.length > 0 \\? err\\.message : 'Internal Server Error'","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"services/datalake/pod-datalake/src/server.ts","lineNumber":324,"sourceCode":"      'File too large' // happens when the file exceeds the limit set by express-fileupload\n    ]\n\n    return !ignoreMessages.includes(err.message)\n  }\n\n  app.use((err: any, _req: any, res: any, _next: any) => {\n    ctx.error(err.message, { code: err.code, message: err.message })\n    if (err instanceof ApiError) {\n      res.status(err.code).send({ code: err.code, message: err.message })\n      return\n    }\n\n    // do not send some errors to analytics\n    if (sendErrorToAnalytics(err)) {\n      Analytics.handleError(err)\n    }\n\n    res.status(500).json({ message: err.message?.length > 0 ? err.message : 'Internal Server Error' })\n  })\n\n  app.get('/api/v1/statistics', (req, res) => {\n    try {\n      const token = req.query.token as string\n      const payload = decodeToken(token)\n      const admin = payload.extra?.admin === 'true'\n      res.setHeader('Content-Type', 'application/json')\n      res.setHeader('Connection', 'keep-alive')\n      res.setHeader('Keep-Alive', 'timeout=5')\n      res.setHeader('Cache-Control', cacheControlNoCache)\n\n      const json = JSON.stringify({\n        metrics: metricsAggregate((ctx as any).metrics),\n        statistics: {\n          cpu: getCPUInfo(),\n          memory: getMemoryInfo()\n        },","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/datalake/pod-datalake/src/server.ts#L306-L342","documentation":"This is the datalake Express global error-handling middleware. When any route handler throws or calls next(err) and the error is not an ApiError, it logs the error, reports it to Analytics (unless the message is a known client-abort case like 'Premature close' or 'File too large'), and responds 500 with err.message, or the literal 'Internal Server Error' when the message is empty or undefined. It exists as the last-resort handler so unhandled server errors always produce a JSON response instead of a hung request.","triggerScenarios":"Any datalake HTTP request (uploads, workspace/object routes, statistics) whose handler throws a non-ApiError: malformed multipart bodies, storage adapter failures, unexpected exceptions in route logic, or body-parsing errors forwarded via next(err).","commonSituations":"S3/blob storage outages mid-upload, express-fileupload limits ('File too large'), clients aborting uploads ('Unexpected end of form', 'Premature close'), or bugs in a handler throwing undefined-message errors.","solutions":["Check the server logs at the same timestamp (ctx.error with code/message) to find the root-cause error thrown by the failing route.","If the message is 'Premature close' / 'Unexpected end of form' / 'File too large', fix the client: complete or restart the upload, or raise the express-fileupload size limit.","If it is a storage or network failure, verify object-storage connectivity and credentials, then retry the request.","If the message is 'Internal Server Error', inspect Analytics entries for the underlying error object, since no useful message reached the response."],"exampleFix":"// before (client ignores aborts and gets opaque 500s)\nawait fetch(uploadUrl, { method: 'PUT', body: stream, signal: undefined })\n// after (client handles aborts explicitly)\nconst ctrl = new AbortController()\ntry {\n  await fetch(uploadUrl, { method: 'PUT', body: stream, signal: ctrl.signal })\n} catch (e) {\n  if (ctrl.signal.aborted) console.warn('upload cancelled')\n  else throw e\n}","handlingStrategy":"try-catch","validationCode":"// client: ensure upload stream is complete and within size limits before sending\nif (fileSize > MAX_UPLOAD_SIZE) throw new Error('File exceeds server upload limit')\nif (stream.destroyed || stream.readableEnded) throw new Error('Upload stream already closed')","typeGuard":"function isApiError(e: unknown): e is { code: number; message: string } {\n  return typeof e === 'object' && e !== null && 'code' in e && typeof (e as any).code === 'number'\n}","tryCatchPattern":"try {\n  const res = await fetch(datalakeUrl, opts)\n  if (!res.ok) {\n    const body = await res.json().catch(() => ({}))\n    if (res.status === 500 && body.message === 'Internal Server Error') throw new Error('datalake 500: check server logs')\n    throw new Error(body.message ?? `datalake ${res.status}`)\n  }\n} catch (e) {\n  // retry idempotent reads; surface message; treat aborts ('Premature close') as client-cancelled\n}","preventionTips":["Keep uploads within the server's express-fileupload size limit","Do not abort requests mid-upload; use resumable uploads for large files","Retry with backoff on 500 for idempotent operations","Monitor datalake server logs for the root-cause message paired with each 500"],"tags":["http","express","server-error","upload"],"backgroundTag":"http-500-unhandled-exception","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}