{"record":{"id":"61cfbfeb32349f34","repo":"hcengineering/platform","slug":"not-found-61cfbf","errorCode":null,"errorMessage":"Not found","messagePattern":"Not found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"services/mail/pod-mail/src/server.ts","lineNumber":48,"sourceCode":"  })()\n}\n\nexport function createServer (endpoints: Endpoint[]): Express {\n  const app = express()\n\n  app.use(cors())\n  app.use(express.json())\n\n  endpoints.forEach((endpoint) => {\n    if (endpoint.type === 'get') {\n      app.get(endpoint.endpoint, catchError(endpoint.handler))\n    } else if (endpoint.type === 'post') {\n      app.post(endpoint.endpoint, catchError(endpoint.handler))\n    }\n  })\n\n  app.use((_req, res, _next) => {\n    res.status(404).send({ message: 'Not found' })\n  })\n\n  app.use((err: any, _req: any, res: any, _next: any) => {\n    if (err instanceof ApiError) {\n      res.status(400).send({ code: err.code, message: err.message })\n      return\n    }\n\n    res.status(500).send({ message: err.message })\n  })\n\n  return app\n}\n\nexport function listen (e: Express, port: number, host?: string): Server {\n  const cb = (): void => {\n    console.log(`Mail service has been started at ${host ?? '*'}:${port}`)\n  }","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/mail/pod-mail/src/server.ts#L30-L66","documentation":"The pod-mail Express server has a catch-all middleware that responds 404 { message: 'Not found' } to any request that did not match a registered endpoint. It is not thrown by handler code — it is the terminal route-matching fallback. It means the URL path or HTTP method did not correspond to any endpoint registered via createServer.","triggerScenarios":"GET/POST to a path not in the endpoint table (e.g. wrong service prefix, wrong port routing to the wrong pod, trailing path segments), or using GET on an endpoint registered with type 'post'.","commonSituations":"Proxy or gateway rewriting paths and dropping/adding prefixes; calling the mail pod on the notification pod's port (or vice versa — both return the identical 404 body); API version path changed after upgrade; typo in endpoint path like /sendmail vs /send-mail.","solutions":["Check the request URL against the endpoint paths registered in pod-mail's main.ts and correct the path or HTTP method.","Confirm the client is hitting the mail pod's host:port, not another pod (pod-mail and pod-notification have identical 404 bodies).","Inspect any reverse-proxy/gateway rewrite rules that may strip or prepend path prefixes.","Log the full incoming req.method + req.originalUrl (temporarily add middleware before the 404 handler) to see what actually reaches the server."],"exampleFix":"// before\nawait fetch('http://mail:3040/send-mail', ...)\n// after (path matching the registered post endpoint)\nawait fetch('http://mail:3040/sendmail', { method: 'POST', ... })","handlingStrategy":"validation","validationCode":"const MAIL_ROUTES = ['/sendmail'] // paths registered by pod-mail\nfunction assertMailRoute(method: string, path: string) {\n  if (method !== 'POST' || !MAIL_ROUTES.includes(path)) throw new Error(`unknown mail route ${method} ${path}`)\n}","typeGuard":null,"tryCatchPattern":"const res = await fetch(url, opts)\nif (res.status === 404) throw new Error(`mail pod has no route for ${opts.method} ${url} — check path/method and target port`)","preventionTips":["Keep endpoint paths in shared constants used by both client and server registration","Pin pod host:port per service in config to avoid cross-pod confusion","Confirm POST vs GET per endpoint before calling"],"tags":["http-404","routing","express","rest"],"backgroundTag":"http-404-not-found","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}