HeyPuter/puter · error · HttpError
bad_request
bad_request
Error message
`uid` must be a non-empty string
What it means
`POST /notif/mark-ack` requires a `uid` field in the JSON body identifying the notification to acknowledge. The controller validates it is a non-empty string before doing any work. This is the first guard in the handler — it fires before the auth check.
Source
Thrown at src/backend/controllers/notification/NotificationController.ts:56
* timestamp; pushes ack event to sockets.
*/
@Post('/mark-ack', {
subdomain: 'api',
requireUserActor: true,
allowFullAccessToken: true,
// 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: {View on GitHub (pinned to 908ec23eda)
Solutions
- Ensure the request body includes `uid` as a non-empty string matching the notification's UID.
- Set `Content-Type: application/json` on the request.
- Pull the UID from the notification object returned by the list-notifications endpoint.
- Add a client-side guard: skip the call if `uid` is falsy.
Example fix
// before
notifEl.ondismiss = () => api.call('notif/mark-ack', {});
// after
notifEl.ondismiss = () => {
if (!notif.uid) return;
api.call('notif/mark-ack', { uid: notif.uid });
}; Defensive patterns
Strategy: validation
Validate before calling
function markAck(uid) {
if (typeof uid !== 'string' || uid.length === 0) return;
return fetch('/api/notif/mark-ack', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ uid }),
});
} Type guard
/** @param {unknown} v @returns {v is string} */
function isNonEmptyString(v) {
return typeof v === 'string' && v.length > 0;
} Prevention
- Guard the dismiss handler: skip the API call when `uid` is missing.
- Use the `uid` field name from the notification object, not `id`.
- Set `Content-Type: application/json` on every POST.
When it happens
Trigger: Calling mark-ack with a body missing `uid`, with `uid` set to a number/empty string/null, or without a JSON Content-Type so the body is unparsed. Common in frontend notification dismiss handlers that forget to pass the notification ID.
Common situations: A notification toast dismiss handler passes the DOM element ID instead of the notification UID; the notification object was null; a test posts `{}` as the body.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/35b22ad03cefc603.
Report an issue: GitHub.