{"record":{"id":"4ac92ab582bee5c0","repo":"HeyPuter/puter","slug":"unauthorized-4ac92a","errorCode":"unauthorized","errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"exception","errorClass":"HttpError","httpStatus":401,"severity":"error","filePath":"src/backend/controllers/feedback/AppFeedbackController.ts","lineNumber":153,"sourceCode":"                legacyCode: 'bad_request',\n            });\n        }\n        if (message.length > RAW_MESSAGE_CAP) {\n            throw new HttpError(\n                400,\n                `\\`message\\` is too long (max ${AppFeedbackService.MESSAGE_MAX_LENGTH} characters)`,\n                { legacyCode: 'bad_request' },\n            );\n        }\n\n        const sourceEnv =\n            body.context === 'app' || body.context === 'web'\n                ? body.context\n                : undefined;\n\n        const userId = req.actor?.user?.id;\n        if (!userId) {\n            throw new HttpError(401, 'Unauthorized', {\n                legacyCode: 'unauthorized',\n            });\n        }\n\n        const service = this.services.appFeedback as AppFeedbackService;\n        await service.submit({\n            userId,\n            app,\n            origin,\n            message,\n            sourceEnv,\n            sourceOrigin: origin ?? null,\n        });\n        res.json({});\n    }\n}\n","sourceCodeStart":135,"sourceCodeEnd":170,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/feedback/AppFeedbackController.ts#L135-L170","documentation":"Thrown by POST /app-feedback when the authenticated actor has no associated user id (req.actor?.user?.id is falsy). The route is gated by requireUserActor and requireVerified, so this fires only when those gates passed but the user object is nonetheless missing an id — an inconsistency in the auth pipeline rather than a normal unauthenticated request.","triggerScenarios":"A request reaches the handler with an actor that is not a user actor (e.g. a service/worker actor that bypassed requireUserActor), or a user actor whose user row failed to load. Also possible during auth refactor where the actor shape changed but a stale token type still satisfies the gate.","commonSituations":"Misconfigured auth middleware after a Puter upgrade that changed actor serialization. A token minted for a since-deleted user. Local dev with a hand-crafted session that skips normal user hydration.","solutions":["Verify the request carries a valid user session token (not an app or anonymous token).","Check that the auth middleware populates req.actor.user.id for the token type in use.","Re-authenticate to mint a fresh user token if the current one predates the running backend version."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await fetch('/app-feedback', { ... }); }\ncatch (e) {\n  if (e?.code === 'unauthorized') { /* re-authenticate the user, then retry once */ await relogin(); return retry(); }\n  throw e;\n}","preventionTips":["Ensure a valid user session token is attached before calling feedback endpoints.","Handle session-expiry signals from the GUI to re-prompt login.","Do not call /app-feedback from app actors or anonymous contexts."],"tags":["auth","unauthorized","feedback","actor"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}