{"record":{"id":"a518165744b8d431","repo":"hcengineering/platform","slug":"not-found-a51816","errorCode":null,"errorMessage":"Not Found","messagePattern":"Not Found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"info","filePath":"services/backup/backup-api-pod/src/server.ts","lineNumber":431,"sourceCode":"      if (err instanceof TokenError) {\n        res.status(401).send()\n        return\n      }\n      ctx.error('statistics error', { err })\n      Analytics.handleError(err)\n      res.status(404).send()\n    }\n  })\n\n  app.get('/', (_req, res) => {\n    res.send(`\n      Huly® Datalake™ <a href=\"https://huly.io\">https://huly.io</a>\n      © 2025 <a href=\"https://hulylabs.com\">Huly Labs</a>\n    `)\n  })\n\n  app.use((_req, res) => {\n    res.status(404).json({ message: 'Not Found' })\n  })\n\n  return {\n    app,\n    close: () => {\n      clearInterval(wsInfoCacheInterval)\n    }\n  }\n}\n\nexport function listen (e: Express, port: number, host?: string): Server {\n  const cb = (): void => {\n    console.log(`Service started at ${host ?? '*'}:${port}`)\n  }\n\n  const server = host !== undefined ? e.listen(port, host, cb) : e.listen(port, cb)\n  server.keepAliveTimeout = KEEP_ALIVE_TIMEOUT * 1000 + 1000\n  server.headersTimeout = KEEP_ALIVE_TIMEOUT * 1000 + 2000","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/backup/backup-api-pod/src/server.ts#L413-L449","documentation":"The catch-all middleware responds 404 with JSON { message: 'Not Found' } for any request that did not match a previously defined route or static handler. It is the terminal fallback of the backup API's router, not an exceptional condition — the requested URL simply has no handler.","triggerScenarios":"Requesting an undefined path such as GET /api/backup (no workspace/file), wrong HTTP method on a defined path (only GET routes exist here), or typos like /api/v2/statistics.","commonSituations":"Clients guessing API paths, health checkers probing endpoints that were removed, or frontends calling an endpoint renamed between service versions.","solutions":["Use one of the defined routes: GET /api/backup/:workspace/:file(*), GET /api/v1/statistics?token=..., or GET /","Fix typos in the URL path and confirm the HTTP method is GET","Check the service version exposes the endpoint you expect","For health checks, probe GET / instead of an invented path"],"exampleFix":"// before\nawait fetch('https://backup.example.com/api/backup') // missing workspace/file\n// after\nawait fetch(`https://backup.example.com/api/backup/${workspaceUuid}/index.json`, { headers: { Authorization: `Bearer ${token}` } })","handlingStrategy":"validation","validationCode":"const KNOWN = [/^\\/api\\/backup\\/[^/]+\\/.+$/, /^\\/api\\/v1\\/statistics$/, /^\\/$/]\nif (!KNOWN.some((re) => re.test(url.pathname))) throw new Error(`Unknown backup API path: ${url.pathname}`)","typeGuard":"function isKnownBackupPath(pathname: string): boolean {\n  return pathname === '/' || pathname.startsWith('/api/backup/') || pathname === '/api/v1/statistics'\n}","tryCatchPattern":"const res = await fetch(url)\nif (res.status === 404) {\n  const body = await res.json().catch(() => null)\n  if (body?.message === 'Not Found') throw new Error(`No such endpoint: ${url}`)\n}","preventionTips":["Only call documented routes (GET /api/backup/:workspace/:file, GET /api/v1/statistics)","Always use GET — other methods fall through to 404","Pin API client versions to the deployed service version","Probe GET / for liveness instead of invented paths"],"tags":["http-404","routing","express"],"backgroundTag":"route-not-found","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}