{"record":{"id":"5f8f5904ac957bdd","repo":"HeyPuter/puter","slug":"not-found-5f8f59","errorCode":"not_found","errorMessage":"User not found","messagePattern":"User not found","errorType":"exception","errorClass":"HttpError","httpStatus":404,"severity":"error","filePath":"src/backend/core/http/middleware/userProtected.ts","lineNumber":172,"sourceCode":"\n    // 2. Fresh user row (bypass cache to catch just-suspended accounts).\n    // `getById` doesn't take options; go through `getByProperty` with\n    // `{ force: true }` to force a primary read.\n    const refreshUser: RequestHandler = async (\n        req: Request,\n        _res: Response,\n        next: NextFunction,\n    ) => {\n        const actor = req.actor;\n        if (!actor?.user?.id)\n            throw new HttpError(401, 'User required', {\n                legacyCode: 'unauthorized',\n            });\n        const user = await userStore.getByProperty('id', actor.user.id, {\n            force: true,\n        });\n        if (!user)\n            throw new HttpError(404, 'User not found', {\n                legacyCode: 'not_found',\n            });\n        if (user.suspended)\n            throw new HttpError(403, 'Account is suspended', {\n                legacyCode: 'account_suspended',\n            });\n        req.userProtected = { user };\n        next();\n    };\n\n    // 3. Password (bcrypt) OR valid OIDC revalidation cookie.\n    //\n    //   - Temp users (no password + no email) pass only when the route was\n    //     registered with `allowTempUsers: true` (delete-own-user).\n    //   - `req.body.password` → bcrypt match against user row. OIDC-only\n    //     accounts bounce with `oidc_revalidation_required` + a\n    //     `revalidate_url` helper so the GUI can open the OIDC popup.\n    //   - Otherwise accept a valid `puter_revalidation` cookie. Expiry,","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/core/http/middleware/userProtected.ts#L154-L190","documentation":"Raised in `refreshUser` when the primary DB read (`getByProperty('id', ..., { force: true })`, deliberately bypassing cache) for the authenticated user's id returns no row. The actor was authenticated against a user that no longer exists in the store.","triggerScenarios":"The account was deleted between authentication and the userProtected call; a data-inconsistency/restore left the actor referencing a dropped user; a test fixture was removed mid-flow.","commonSituations":"Concurrent account deletion while a session is still active; DB replication lag or a partial migration; a stale actor/token retained after deletion.","solutions":["Sign out and re-authenticate / sign up again — the session is orphaned.","If admin, inspect the user store for the missing id and reconcile.","Do not reuse sessions after deleting the owning account."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await call(); }\ncatch (e) {\n  if (e.code === 'not_found' && /user/i.test(e.message)) { logout(); routeToSignup(); return; }\n  throw e;\n}","preventionTips":["Drop sessions immediately after deleting the owning account.","Don't reuse orphaned sessions/tokens.","Investigate store integrity if legitimate users vanish."],"tags":["user-protected","not-found","data-integrity","account"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}