immich-app/immich · error · BadRequestException
Notification not found
Error message
Notification not found
What it means
NotificationService.get fetches a single notification by id after the access check passes; if notificationRepository.get returns null (no such notification, or it does not belong to a context the user can read), it throws 400 BadRequestException 'Notification not found'. The 400 (rather than 404) is an Immich convention for these lookups.
Source
Thrown at server/src/services/notification.service.ts:58
}
async updateAll(auth: AuthDto, dto: NotificationUpdateAllDto) {
await this.requireAccess({ auth, ids: dto.ids, permission: Permission.NotificationUpdate });
await this.notificationRepository.updateAll(dto.ids, {
readAt: dto.readAt,
});
}
async deleteAll(auth: AuthDto, dto: NotificationDeleteAllDto) {
await this.requireAccess({ auth, ids: dto.ids, permission: Permission.NotificationDelete });
await this.notificationRepository.deleteAll(dto.ids);
}
async get(auth: AuthDto, id: string) {
await this.requireAccess({ auth, ids: [id], permission: Permission.NotificationRead });
const item = await this.notificationRepository.get(id);
if (!item) {
throw new BadRequestException('Notification not found');
}
return mapNotification(item);
}
async update(auth: AuthDto, id: string, dto: NotificationUpdateDto) {
await this.requireAccess({ auth, ids: [id], permission: Permission.NotificationUpdate });
const item = await this.notificationRepository.update(id, {
readAt: dto.readAt,
});
return mapNotification(item);
}
async delete(auth: AuthDto, id: string) {
await this.requireAccess({ auth, ids: [id], permission: Permission.NotificationDelete });
await this.notificationRepository.delete(id);
}
@OnJob({ name: JobName.NotificationsCleanup, queue: QueueName.BackgroundTask })View on GitHub (pinned to 199723261c)
Solutions
- Refresh the notification list (GET /notifications) and operate only on current ids.
- Handle the 400 gracefully in the client and drop the stale reference.
- Confirm the id is a valid UUID.
Example fix
// before
api.notifications.get('stale-id');
// after
const list = await api.notifications.list();
await api.notifications.get(list[0].id); Defensive patterns
Strategy: validation
Validate before calling
const list = await api.notificationApi.list();
if (!list.some((n) => n.id === id)) {
throw new Error(`Notification ${id} not found`);
}
await api.notificationApi.get(id); Type guard
const notificationExists = (id: string, items: { id: string }[]) =>
items.some((n) => n.id === id); Try / catch
try {
return await api.notificationApi.get(id);
} catch (e) {
if (e.status === 400 && /Notification not found/.test(e.message)) {
// refresh the list and drop the stale id
} else throw e;
} Prevention
- Operate on notifications from a freshly fetched list.
- Handle 400 by invalidating the local notification cache.
- Use UUID validation client-side.
When it happens
Trigger: GET /notifications/{id} for an id that does not exist or that the access scope does not cover. Common with a stale notification id in the UI after it was deleted, or a hand-crafted request.
Common situations: User dismissed/deleted a notification but the client still references it; wrong id copied; another admin cleared all notifications.
Related errors
- Library ${id} not found
- assetIds, albumId, or userId is required
- Invalid job name
- Invalid import path: ${path.message}
- User not found
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/455ab1b82d515ae9.
Report an issue: GitHub.