{"record":{"id":"e694e0adb275c9ac","repo":"thedotmack/claude-mem","slug":"notfound-e694e0","errorCode":"NotFound","errorMessage":"Cannot ${req.method} ${req.path}","messagePattern":"Cannot (.+?) (.+?)","errorType":"http","errorClass":null,"httpStatus":404,"severity":"error","filePath":"src/services/server/ErrorHandler.ts","lineNumber":61,"sourceCode":"\n  logger.error('HTTP', `Error handling ${req.method} ${req.path}`, {\n    statusCode,\n    error: err.message,\n    code: err instanceof AppError ? err.code : undefined\n  }, err);\n\n  const response = createErrorResponse(\n    err.name || 'Error',\n    err.message,\n    err instanceof AppError ? err.code : undefined,\n    err instanceof AppError ? err.details : undefined\n  );\n\n  res.status(statusCode).json(response);\n};\n\nexport function notFoundHandler(req: Request, res: Response): void {\n  res.status(404).json(createErrorResponse(\n    'NotFound',\n    `Cannot ${req.method} ${req.path}`\n  ));\n}\n","sourceCodeStart":43,"sourceCodeEnd":66,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/e2d1df569a8f04075d40e92461128ece7cf04c82/src/services/server/ErrorHandler.ts#L43-L66","documentation":"This is the Express catch-all registered after all real routes: any request matching no route falls through to notFoundHandler and gets 404 'Cannot <METHOD> <path>'. It means the method+path combination is not registered at all — a routing mistake, not a missing data resource.","triggerScenarios":"Typos in paths, missing the /api or /v1 prefix, wrong HTTP method (PUT where only PATCH is registered), doubled path segments, or a proxy rewriting/stripping the prefix before the request reaches the server.","commonSituations":"Client/server version skew after a route was renamed; hitting the worker port with server URLs or vice versa; reverse proxies stripping path prefixes; trailing-slash or case mismatches.","solutions":["Compare the echoed method and path in the message against the server's registered routes","Fix the base URL or prefix (e.g. /api/... management routes vs /v1/... data routes)","Use the correct HTTP method for the route"],"exampleFix":"// before\nfetch(`${base}/v1/memory/${id}`); // 404 Cannot GET /v1/memory/abc (singular, unregistered)\n\n// after\nfetch(`${base}/v1/memories/${id}`); // 200","handlingStrategy":"validation","validationCode":"const ROUTES = {\n  listProjects: '/v1/projects',\n  getMemory: (id: string) => `/v1/memories/${encodeURIComponent(id)}`,\n  search: '/v1/search',\n  readiness: '/api/readiness',\n} as const;\n// single source of truth for paths; catches typos and prefix mistakes before any request\nconst url = new URL(ROUTES.getMemory(id), base);","typeGuard":"function isRouteNotFound(status: number, body: unknown): body is { error: 'NotFound'; message: string } {\n  return status === 404 && typeof body === 'object' && body !== null && (body as { error?: string }).error === 'NotFound' && typeof (body as { message?: string }).message === 'string' && (body as { message: string }).message.startsWith('Cannot ');\n}","tryCatchPattern":"const res = await fetch(url, init);\nconst body = await res.json().catch(() => ({}));\nif (isRouteNotFound(res.status, body)) {\n  throw new Error(`route bug: no handler for \"${body.message}\" — check method (${init.method ?? 'GET'}), path prefix (/api vs /v1), and client/server version`);\n}","preventionTips":["Keep route constants in one module shared by all clients","Pin client and server versions so route sets match","Watch proxy rewrites: stripped prefixes produce exactly this 404"],"tags":["http-404","express","routing"],"backgroundTag":"http-404-route-not-found","analyzedSha":"e2d1df569a8f04075d40e92461128ece7cf04c82","analyzedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}