{"record":{"id":"6a0597855612c2e9","repo":"HeyPuter/puter","slug":"forbidden-6a0597","errorCode":"forbidden","errorMessage":"Account suspended","messagePattern":"Account suspended","errorType":"exception","errorClass":"HttpError","httpStatus":403,"severity":"error","filePath":"src/backend/core/http/middleware/gates.ts","lineNumber":396,"sourceCode":"            403,\n            'Please verify your phone number to continue',\n            {\n                legacyCode: 'phone_verification_required' as never,\n            },\n        );\n    }\n    if (user?.requires_card_verification) {\n        throw new HttpError(403, 'Please verify your card to continue', {\n            legacyCode: 'card_verification_required' as never,\n        });\n    }\n};\n\nexport const assertNotSuspended = (\n    user: { suspended?: unknown } | undefined,\n): void => {\n    if (user?.suspended) {\n        throw new HttpError(403, 'Account suspended', {\n            legacyCode: 'forbidden',\n        });\n    }\n};\n\n/**\n * Reject unless the actor is acting through one of the named apps.\n * App-under-user actors are permitted iff `actor.app.uid` is in the allowList;\n * non-app actors are rejected.\n *\n * Implies `requireAuth`. Doesn't pair sensibly with `requireUserActor` (a\n * user-only actor has no app), but if both are set we reject loudly here.\n */\nexport const allowedAppIdsGate = (\n    allowedAppUids: readonly string[],\n): RequestHandler => {\n    const allowList = new Set(allowedAppUids);\n    return (req, _res, next) => {","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/core/http/middleware/gates.ts#L378-L414","documentation":"Raised by `assertNotSuspended` when the user row's `suspended` flag is truthy. Suspended accounts are blocked from all gated access and surface under the generic `forbidden` legacy code.","triggerScenarios":"Any request from an account whose `suspended` flag is set hits a route guarded by `assertNotSuspended` (or the userProtected chain's suspension check).","commonSituations":"Account suspended by an admin or automated moderation for a ToS/abuse violation; a test account left suspended; flag set erroneously.","solutions":["Contact support to resolve the suspension.","As admin, clear the `suspended` flag on the user row once resolved.","Verify the suspension was intended and not a stale flag."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"const isSuspended = (u) => !!(u && u.suspended);","tryCatchPattern":"try { await call(); }\ncatch (e) {\n  if (e.code === 'forbidden' && /suspended/i.test(e.message)) { showAccountSuspended(); return; }\n  throw e;\n}","preventionTips":["Treat suspended accounts as terminal client-side; direct users to support.","Don't auto-retry suspended-account requests.","Clear the flag via admin tooling only after the underlying issue is resolved."],"tags":["account","suspended","forbidden","moderation"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}