immich-app/immich · warning · BadRequestException

Notification not found

Error message

Notification not found

What it means

Thrown by NotificationService.get when no notification exists for the given id, after access control passes. The repository returns undefined and the service raises a BadRequestException instead of returning a null/mapped object. In practice this means the notification id is unknown, stale, or already deleted.

Solutions

  1. Verify the notification id is correct and still exists (e.g. re-fetch the notification list)
  2. Refresh the client's notification list to drop stale ids before retrying
  3. Handle 400 'Notification not found' on the client by removing the item from local state
  4. If ids come from another environment, use the correct instance's ids

Example fix

// before
const n = await api.notificationApi.getNotificationById(staleId); // throws 400
// after
const list = await api.notificationApi.getNotifications();
const n = list.find(x => x.id === staleId);
if (n) { /* use it */ } else { removeFromLocalState(staleId); }
Defensive patterns

Strategy: validation

Validate before calling

const list = await api.notificationApi.getNotifications();
if (!list.some(n => n.id === id)) {
  throw new Error(`Notification ${id} no longer exists; refresh list`);
}

Type guard

function isKnownNotification(id, notifications) {
  return typeof id === 'string' && id.length > 0 &&
    notifications.some(n => n && typeof n.id === 'string' && n.id === id);
}

Try / catch

try {
  const n = await api.notificationApi.getNotificationById(id);
  return n;
} catch (e) {
  if (String(e.message).includes('Notification not found')) {
    removeFromLocalState(id); // drop stale id, optionally refetch list
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: GET /notifications/:id with an id that does not exist in the database, was already dismissed/deleted, or is malformed/points to another instance's data.

Common situations: Client caches or bookmarks a notification id that has since been removed; UI re-loads a stale list after cleanup job deleted rows; copy-pasted id from another environment; double-click causing the first request to delete/consume the notification.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/455ab1b82d515ae9. Report an issue: GitHub.

Appendix: 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 e55ac299a4)