{"record":{"id":"a5d76d00099a4cda","repo":"HeyPuter/puter","slug":"not-found-a5d76d","errorCode":"not_found","errorMessage":"Notification not found","messagePattern":"Notification not found","errorType":"http","errorClass":"HttpError","httpStatus":404,"severity":"error","filePath":"src/backend/drivers/notification/NotificationDriver.ts","lineNumber":115,"sourceCode":"            userId: actor.user.id,\n            value,\n        });\n        return this.#toClient(created);\n    }\n\n    async read(args: Record<string, unknown>): Promise<unknown> {\n        const actor = this.#requireUserActor();\n        const uid = (args.uid ?? args.id) as string | undefined;\n        if (!uid)\n            throw new HttpError(400, 'Missing `uid`', {\n                legacyCode: 'bad_request',\n            });\n\n        const row = await this.stores.notification.getByUid(String(uid), {\n            userId: actor.user.id,\n        });\n        if (!row)\n            throw new HttpError(404, 'Notification not found', {\n                legacyCode: 'not_found',\n            });\n        return this.#toClient(row);\n    }\n\n    async select(args: Record<string, unknown>): Promise<unknown[]> {\n        const actor = this.#requireUserActor();\n        const limit = Math.min(\n            Number(args.limit ?? MAX_SELECT_LIMIT),\n            MAX_SELECT_LIMIT,\n        );\n        const predicate = args.predicate as string | string[] | undefined;\n\n        const predicateName = Array.isArray(predicate)\n            ? predicate[0]\n            : predicate;\n\n        // Route predicate → store query params","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/notification/NotificationDriver.ts#L97-L133","documentation":"NotificationDriver.read() resolved the uid but no notification row exists for that uid owned by the calling user (the lookup is scoped by actor.user.id). This is an owner-scoped 404 — the notification either does not exist, was deleted, or belongs to a different user.","triggerScenarios":"Passing a uid that was never created; a uid from another user's notification list; a uid of an already-deleted notification; a malformed uid that simply does not match.","commonSituations":"Stale uid cached in the UI after the notification was acknowledged/cleared; cross-user uid leak; test using a uid from a different account; uid truncated/corrupted in transit.","solutions":["Verify the uid is from the current user's own notification list (e.g. from select).","Treat a 404 as 'already gone' and clear it from the UI rather than retrying.","Refresh the notification list to get live uids."],"exampleFix":"// before\nconst n = await notifications.read({ uid: staleUid });\n\n// after\ntry {\n  const n = await notifications.read({ uid: notif.uid });\n} catch (e) {\n  if (e.code === 'not_found') { /* drop from UI */ }\n  else throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const n = await notifications.read({ uid });\n} catch (e) {\n  if (e.status === 404 && e.code === 'not_found') {\n    // already gone — remove from UI, do not retry\n  } else throw e;\n}","preventionTips":["Treat notification 404 as transient/already-resolved, not an error to surface loudly.","Refresh the notification list to obtain live uids rather than reusing stale ones.","Scope uid lookups to the current user's own select results."],"tags":["notifications","not-found","validation"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}