{"record":{"id":"9af76cc2ee689094","repo":"HeyPuter/puter","slug":"temporary-account","errorCode":"temporary_account","errorMessage":"Temporary account","messagePattern":"Temporary account","errorType":"exception","errorClass":"HttpError","httpStatus":403,"severity":"error","filePath":"src/backend/core/http/middleware/userProtected.ts","lineNumber":207,"sourceCode":"    //     `revalidate_url` helper so the GUI can open the OIDC popup.\n    //   - Otherwise accept a valid `puter_revalidation` cookie. Expiry,\n    //     `purpose === 'revalidate'`, matching `user_uuid` all required.\n    //   - Password account, neither credential → 403 `password_required`.\n    const verifyIdentity: RequestHandler = async (\n        req: Request,\n        _res: Response,\n        next: NextFunction,\n    ) => {\n        const user = req.userProtected?.user;\n        if (!user)\n            throw new HttpError(500, 'user-protected state missing', {\n                legacyCode: 'internal_error',\n            });\n\n        const isTemp = user.password === null && user.email === null;\n        if (isTemp) {\n            if (allowTemp) return next();\n            throw new HttpError(403, 'Temporary account', {\n                legacyCode: 'temporary_account',\n            });\n        }\n\n        const bodyPassword =\n            typeof req.body?.password === 'string' ? req.body.password : null;\n        if (bodyPassword) {\n            if (user.password === null) {\n                const fields = await buildRevalidateFields(\n                    config,\n                    oidcService,\n                    user,\n                );\n                throw new HttpError(403, 'OIDC revalidation required', {\n                    legacyCode: 'oidc_revalidation_required',\n                    fields,\n                });\n            }","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/core/http/middleware/userProtected.ts#L189-L225","documentation":"Raised in `verifyIdentity` when the user has neither a password nor an email (a temp/anonymous account) and the route was NOT registered with `allowTempUsers: true`. Sensitive operations require a real account; temp accounts are only admitted where the route explicitly opts in (e.g. delete-own-user for temp accounts).","triggerScenarios":"A temp account (no password, no email) hits a userProtected route that did not set `allowTempUsers: true`.","commonSituations":"A guest/temp session used to attempt account operations; a route that should allow temp accounts but wasn't opted in.","solutions":["Upgrade the temp account to a real one by setting an email and/or password.","If temp users should pass this route, register it with `allowTempUsers: true`.","Gate the UI so temp accounts cannot reach the sensitive flow."],"exampleFix":"// before\nconst gate = createUserProtectedGate(deps);\n// after\nconst gate = createUserProtectedGate(deps, { allowTempUsers: true });","handlingStrategy":"validation","validationCode":"// Gate the UI on account type before reaching the sensitive flow:\nconst isTempAccount = (u) => u && u.password == null && u.email == null;\nif (isTempAccount(user) && !routeAllowsTemp) { promptUpgradeAccount(); }","typeGuard":"const isTempAccount = (u) => !!(u && u.password == null && u.email == null);","tryCatchPattern":"try { await call(); }\ncatch (e) {\n  if (e.code === 'temporary_account') { promptUpgradeAccount(); return; }\n  throw e;\n}","preventionTips":["Upgrade temp accounts (set email/password) before sensitive operations.","Only opt routes into allowTempUsers when temp access is genuinely intended.","Hide sensitive flows from temp accounts in the UI."],"tags":["account","temp","user-protected","anonymous"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}