{"record":{"id":"06fa8b07f1cf9f22","repo":"HeyPuter/puter","slug":"unauthorized-06fa8b","errorCode":"unauthorized","errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":"HttpError","httpStatus":401,"severity":"error","filePath":"src/backend/controllers/notification/NotificationController.ts","lineNumber":62,"sourceCode":"        // Fires per notification interaction, so the ceiling stays\n        // generous — it is here to catch a loop, not to pace a user.\n        rateLimit: {\n            scope: 'notification-mark',\n            limit: 300,\n            window: 60_000,\n            key: 'user',\n        },\n    })\n    async markAck(req: Request, res: Response): Promise<void> {\n        const uid = req.body?.uid;\n        if (typeof uid !== 'string' || uid.length === 0) {\n            throw new HttpError(400, '`uid` must be a non-empty string', {\n                legacyCode: 'bad_request',\n            });\n        }\n        const userId = req.actor?.user?.id;\n        if (!userId)\n            throw new HttpError(401, 'Unauthorized', {\n                legacyCode: 'unauthorized',\n            });\n\n        const notifService = this.services.notification as unknown as\n            NotificationService | undefined;\n        if (notifService?.markAcknowledged) {\n            await notifService.markAcknowledged(uid, userId);\n        } else {\n            // Fallback: direct store call if service isn't wired\n            await (\n                this.stores as Record<string, unknown> as {\n                    notification: {\n                        markAcknowledged: (\n                            uid: string,\n                            userId: number,\n                        ) => Promise<boolean>;\n                    };\n                }","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/notification/NotificationController.ts#L44-L80","documentation":"`POST /notif/mark-ack` could not resolve a user ID from `req.actor.user.id`. Although the route is decorated with `requireUserActor: true` (which should block unauthenticated requests earlier in the pipeline), this is a defensive secondary guard. If reached, the actor is missing or malformed.","triggerScenarios":"The route middleware that enforces `requireUserActor` was bypassed or misconfigured; the auth token resolved to an actor without a `user` property (e.g., an app-only actor); a session expired between middleware and handler execution.","commonSituations":"A misconfigured middleware chain that lets an anonymous request through; a stale or partially-valid token; an extension that overrode the actor shape; running tests without proper auth setup.","solutions":["Ensure the request includes a valid user session token or full-access API token.","If this fires despite correct auth, check that the `requireUserActor` middleware is wired for this route.","Re-authenticate to obtain a fresh token and retry.","Verify the actor middleware populates `req.actor.user.id` for your token type."],"exampleFix":"// before — calling without a valid session\nawait fetch('/api/notif/mark-ack', {\n  method: 'POST',\n  body: JSON.stringify({ uid }),\n});\n\n// after — include auth token\nawait fetch('/api/notif/mark-ack', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json',\n    'Authorization': `Bearer ${sessionToken}`,\n  },\n  body: JSON.stringify({ uid }),\n});","handlingStrategy":"validation","validationCode":"// Verify auth state before calling\nif (!sessionToken) {\n  redirectToLogin();\n  return;\n}\nawait fetch('/api/notif/mark-ack', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json',\n    'Authorization': `Bearer ${sessionToken}`,\n  },\n  body: JSON.stringify({ uid }),\n});","typeGuard":null,"tryCatchPattern":"try {\n  await fetch('/api/notif/mark-ack', { /* ... with auth ... */ });\n} catch (e) {\n  if (e.code === 'unauthorized') {\n    redirectToLogin();\n  } else throw e;\n}","preventionTips":["Check for a valid session token before firing notification handlers.","If this fires despite correct auth, report it as a middleware bug — `requireUserActor` should catch it first.","Re-authenticate on 401 responses."],"tags":["authentication","notifications","http-401","unauthorized","middleware"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}