{"record":{"id":"ab48a00e0b363b72","repo":"typicode/json-server","slug":"not-found","errorCode":null,"errorMessage":"Not Found","messagePattern":"Not Found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"src/app.ts","lineNumber":162,"sourceCode":"\n  app.put('/:name', withBody(service.update.bind(service)))\n\n  app.put('/:name/:id', withIdAndBody(service.updateById.bind(service)))\n\n  app.patch('/:name', withBody(service.patch.bind(service)))\n\n  app.patch('/:name/:id', withIdAndBody(service.patchById.bind(service)))\n\n  app.delete('/:name/:id', async (req, res, next) => {\n    const { name = '', id = '' } = req.params\n    res.locals['data'] = await service.destroyById(name, id, req.query['_dependent'])\n    next?.()\n  })\n\n  app.use('/:name', (req, res) => {\n    const { data } = res.locals\n    if (data === undefined) {\n      res.status(404).json({ error: 'Not Found' })\n    } else {\n      if (req.method === 'POST') res.status(201)\n      res.json(data)\n    }\n  })\n\n  return app\n}\n","sourceCodeStart":144,"sourceCodeEnd":171,"githubUrl":"https://github.com/typicode/json-server/blob/89a34a44b7a6a5311dc84f3b8a1b8b45c0905aea/src/app.ts#L144-L171","documentation":"This 404 is produced by the terminal middleware at src/app.ts:159-167 that every /:name route falls through to. Each handler stores its result in res.locals['data']; when that value is undefined the middleware answers {\"error\":\"Not Found\"}. undefined is the Service layer's signal that the named resource or the record with that id does not exist in the lowdb JSON file, so one response covers both an unknown collection and an unknown id.","triggerScenarios":"GET /users when the db JSON has no \"users\" top-level key; GET /posts/999 or DELETE /posts/999 for an id that does not exist; a singular/plural mismatch such as GET /post instead of /posts; a case mismatch such as /Posts, since the resource name is matched exactly against the db key.","commonSituations":"Client and server disagree on the resource name (typo, singular vs plural, casing); the lowdb JSON file was reset, moved, or pointed at the wrong path so previously known ids vanish; the record was deleted by another client between read and write; tests run against a fresh empty db expecting seeded fixtures.","solutions":["Check that the resource name matches a top-level key in the db JSON file exactly, including pluralization and case","List the collection first (GET /:name) and confirm the id exists before calling /:name/:id","If the db file was reset or moved, re-seed it or point the app at the correct JSON file","Treat 404 in the client as a normal 'resource absent' signal instead of retrying the same call"],"exampleFix":"// before\nconst res = await fetch('/posts/999')\nif (!res.ok) throw new Error(String(res.status))\n\n// after\nconst res = await fetch('/posts/999')\nif (res.status === 404) {\n  // record absent: create it or report to the user\n}","handlingStrategy":"type-guard","validationCode":"// Probe for existence before acting on a specific id\nconst res = await fetch(`/posts/${encodeURIComponent(id)}`)\nif (res.status === 404) {\n  // create the record or skip, instead of issuing the write\n}","typeGuard":"async function resourceExists(name: string, id: string): Promise<boolean> {\n  const res = await fetch(`/${name}/${encodeURIComponent(id)}`)\n  return res.ok\n}\n// usage: (await resourceExists('posts', id)) && await updateById(id, patch)","tryCatchPattern":"// This is an HTTP 404 response, not a thrown exception\ntry {\n  const res = await fetch(`/posts/${id}`)\n  if (!res.ok && res.status !== 404) throw new Error(`unexpected ${res.status}`)\n  if (res.status === 404) {\n    // absent collection or id: seed, recreate, or surface 'not found'\n  }\n} catch (e) {\n  // network-level failure only; 404 is handled above\n}","preventionTips":["Derive resource names from one shared constant so client and db keys cannot diverge","Seed the db JSON file in setup scripts and assert expected keys in test fixtures","Treat 404 as an expected outcome for GET/DELETE-by-id flows, not a crash","Confirm the db file path the server uses matches the one you inspected by hand"],"tags":["http-404","not-found","resource-missing","rest-api"],"backgroundTag":"http-404-not-found","analyzedSha":"89a34a44b7a6a5311dc84f3b8a1b8b45c0905aea","analyzedAt":"2026-08-25T10:20:06.751Z","schemaVersion":2},"datasetVersion":"2026-08-25T11:17:15.655Z"}