HeyPuter/puter · error · HttpError
unauthorized
unauthorized
Error message
Unauthorized
What it means
`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.
Source
Thrown at src/backend/controllers/notification/NotificationController.ts:62
// Fires per notification interaction, so the ceiling stays
// generous — it is here to catch a loop, not to pace a user.
rateLimit: {
scope: 'notification-mark',
limit: 300,
window: 60_000,
key: 'user',
},
})
async markAck(req: Request, res: Response): Promise<void> {
const uid = req.body?.uid;
if (typeof uid !== 'string' || uid.length === 0) {
throw new HttpError(400, '`uid` must be a non-empty string', {
legacyCode: 'bad_request',
});
}
const userId = req.actor?.user?.id;
if (!userId)
throw new HttpError(401, 'Unauthorized', {
legacyCode: 'unauthorized',
});
const notifService = this.services.notification as unknown as
NotificationService | undefined;
if (notifService?.markAcknowledged) {
await notifService.markAcknowledged(uid, userId);
} else {
// Fallback: direct store call if service isn't wired
await (
this.stores as Record<string, unknown> as {
notification: {
markAcknowledged: (
uid: string,
userId: number,
) => Promise<boolean>;
};
}View on GitHub (pinned to 908ec23eda)
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.
Example fix
// before — calling without a valid session
await fetch('/api/notif/mark-ack', {
method: 'POST',
body: JSON.stringify({ uid }),
});
// after — include auth token
await fetch('/api/notif/mark-ack', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${sessionToken}`,
},
body: JSON.stringify({ uid }),
}); Defensive patterns
Strategy: validation
Validate before calling
// Verify auth state before calling
if (!sessionToken) {
redirectToLogin();
return;
}
await fetch('/api/notif/mark-ack', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${sessionToken}`,
},
body: JSON.stringify({ uid }),
}); Try / catch
try {
await fetch('/api/notif/mark-ack', { /* ... with auth ... */ });
} catch (e) {
if (e.code === 'unauthorized') {
redirectToLogin();
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/06fa8b07f1cf9f22.
Report an issue: GitHub.