{"record":{"id":"36b2702b45841d7b","repo":"thedotmack/claude-mem","slug":"notfound-36b270","errorCode":"NotFound","errorMessage":"Project not found","messagePattern":"Project not found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"error","filePath":"src/server/routes/v1/ServerV1Routes.ts","lineNumber":110,"sourceCode":"      this.audit(req, 'projects.list');\n    });\n\n    app.post('/v1/projects', writeAuth, this.handleCreate(CreateProjectSchema, (req, res, body) => {\n      if (req.authContext?.projectId) {\n        res.status(403).json({ error: 'Forbidden', message: 'Project-scoped API keys cannot create projects' });\n        return;\n      }\n      const project = new ProjectsRepository(this.options.getDatabase()).create(body);\n      this.audit(req, 'project.create', project.id);\n      res.status(201).json({ project });\n    }));\n\n    app.get('/v1/projects/:id', readAuth, (req, res) => {\n      const id = this.routeParam(req.params.id);\n      if (!this.ensureProjectAllowed(req, res, id)) return;\n      const project = new ProjectsRepository(this.options.getDatabase()).getById(id);\n      if (!project) {\n        res.status(404).json({ error: 'NotFound', message: 'Project not found' });\n        return;\n      }\n      this.audit(req, 'project.read', project.id);\n      res.json({ project });\n    });\n\n    app.post('/v1/sessions/start', writeAuth, this.handleCreate(CreateServerSessionSchema, (req, res, body) => {\n      if (!this.ensureProjectAllowed(req, res, body.projectId)) return;\n      const session = new ServerSessionsRepository(this.options.getDatabase()).create(body);\n      this.audit(req, 'session.start', session.id, session.projectId);\n      res.status(201).json({ session });\n    }));\n\n    app.post('/v1/sessions/:id/end', writeAuth, (req, res) => {\n      const id = this.routeParam(req.params.id);\n      const repo = new ServerSessionsRepository(this.options.getDatabase());\n      const existing = repo.getById(id);\n      if (!existing) {","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/e2d1df569a8f04075d40e92461128ece7cf04c82/src/server/routes/v1/ServerV1Routes.ts#L92-L128","documentation":"GET /v1/projects/:id loads the project via ProjectsRepository.getById(id); a null return yields 404 NotFound 'Project not found'. The 404 fires only after ensureProjectAllowed passes, so even a correctly-scoped key gets 404 when the row is unknown or was deleted.","triggerScenarios":"GET /v1/projects/<id> where the id does not exist: typo in the URL, a stale id from another environment's database, or a project deleted between listing and fetching.","commonSituations":"Environment drift (staging ids used against prod); hardcoded project ids in scripts; a project concurrently deleted by another client.","solutions":["List projects with GET /v1/projects and copy a current id (project-scoped keys see only their own project)","Verify the client points at the server/database where the project lives","Treat 404 as terminal for that id: re-list and use a fresh one instead of retrying"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"async function getProjectOrFail(base: string, key: string, id: string) {\n  const res = await fetch(`${base}/v1/projects/${encodeURIComponent(id)}`, { headers: { Authorization: `Bearer ${key}` } });\n  if (res.status === 404) {\n    const { projects } = await (await fetch(`${base}/v1/projects`, { headers: { Authorization: `Bearer ${key}` } })).json();\n    throw new Error(`project ${id} not found; available: ${projects.map((p: { id: string }) => p.id).join(', ')}`);\n  }\n  return res.json();\n}","typeGuard":"function isNotFoundResponse(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';\n}","tryCatchPattern":"const res = await fetch(url, { headers });\nconst body = await res.json().catch(() => ({}));\nif (isNotFoundResponse(res.status, body)) {\n  // terminal: drop cached id, re-list projects, do not retry the same id\n  cache.delete(id);\n  return null;\n}","preventionTips":["Fetch project ids dynamically via GET /v1/projects instead of hardcoding","Keep one config source of truth per environment for ids","Treat 404 as terminal, never as a retryable error"],"tags":["http-404","projects","rest"],"backgroundTag":"resource-not-found","analyzedSha":"e2d1df569a8f04075d40e92461128ece7cf04c82","analyzedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}