{"record":{"id":"2f2ea5320b16c85a","repo":"iflytek/astron-agent","slug":"notification-mark-read-failed","errorCode":"NOTIFICATION_MARK_READ_FAILED","errorMessage":"NOTIFICATION_MARK_READ_FAILED","messagePattern":"NOTIFICATION_MARK_READ_FAILED","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/notification/impl/NotificationServiceImpl.java","lineNumber":104,"sourceCode":"            throw new BusinessException(ResponseEnum.PARAMETER_ERROR);\n        }\n\n        try {\n            if (Boolean.TRUE.equals(request.getMarkAll())) {\n                // Mark all unread messages as read\n                markAllNotificationsAsRead(receiverUid);\n            } else if (!CollectionUtils.isEmpty(request.getNotificationIds())) {\n                // Mark specific messages as read\n                markSpecificNotificationsAsRead(receiverUid, request.getNotificationIds());\n            }\n\n            log.info(\"Notifications marked as read successfully, receiverUid: {}, markAll: {}, notificationIds: {}\",\n                    receiverUid, request.getMarkAll(), request.getNotificationIds());\n\n            return true;\n        } catch (Exception e) {\n            log.error(\"Failed to mark notifications as read, receiverUid: {}\", receiverUid, e);\n            throw new BusinessException(ResponseEnum.NOTIFICATION_MARK_READ_FAILED);\n        }\n    }\n\n    @Override\n    @Transactional\n    @DistributedLock(\n            key = \"notification:delete:#{#receiverUid}\",\n            waitTime = 2L,\n            leaseTime = 5L,\n            failStrategy = DistributedLock.FailStrategy.CONTINUE,\n            description = \"Lock for deleting user messages\")\n    public boolean deleteNotification(String receiverUid, Long notificationId) {\n        if (receiverUid == null || notificationId == null) {\n            throw new BusinessException(ResponseEnum.PARAMETER_ERROR);\n        }\n\n        try {\n            int deleted = notificationDataService.deleteUserNotification(receiverUid, notificationId);","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/notification/impl/NotificationServiceImpl.java#L86-L122","documentation":"Any unexpected exception thrown while marking notifications as read (lock issues, data-layer errors, NPEs) is caught, logged, and rethrown as BusinessException(ResponseEnum.NOTIFICATION_MARK_READ_FAILED). It indicates the mark-read operation failed server-side, not a validation problem.","triggerScenarios":"Database write failure in notificationDataService while updating read status; distributed lock contention/timeout around markNotificationsAsRead; NPE when request or request.getNotificationIds() is null (bypassing the uid-only validation).","commonSituations":"DB connection pool exhausted during traffic spikes; Redis lock service unavailable; clients sending markAll=null with notificationIds=null causing internal NPE.","solutions":["Check server logs for the logged 'Failed to mark notifications as read' stack trace to find the root cause.","Ensure the request sets either markAll=true or a non-empty notificationIds list.","Verify database and distributed-lock (Redis) services are healthy; retry after transient failures."],"exampleFix":"// before\n{\"receiverUid\":\"u1\"} // markAll null, notificationIds null -> NPE -> MARK_READ_FAILED\n// after\n{\"receiverUid\":\"u1\",\"markAll\":true}","handlingStrategy":"try-catch","validationCode":"if (!req || (!req.markAll && (req.notificationIds == null || req.notificationIds.length === 0))) { throw new Error('provide markAll or notificationIds'); }","typeGuard":null,"tryCatchPattern":"try { markNotificationsAsRead(uid, req); } catch (BusinessException e) { if (e.getCode() == ResponseEnum.NOTIFICATION_MARK_READ_FAILED.getCode()) { /* check server logs; retry after backoff */ } }","preventionTips":["Always set markAll or a non-empty notificationIds list to avoid internal NPEs.","Monitor DB and Redis lock service health.","Retry with backoff on transient failures."],"tags":["notification","database"],"backgroundTag":"database-write-failed","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}