{"record":{"id":"398c36df848660b8","repo":"apereo/cas","slug":"notification-sent-to-rejected-with-error","errorCode":null,"errorMessage":"Notification [{}] sent to [{}] rejected with error: [{}]","messagePattern":"Notification \\[(.+?)\\] sent to \\[(.+?)\\] rejected with error: \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-notifications-apn/src/main/java/org/apereo/cas/notifications/APNMessagingNotificationSender.java","lineNumber":46,"sourceCode":"    @Override\n    @SuppressWarnings(\"FutureReturnValueIgnored\")\n    public boolean notify(final Principal principal, final Map<String, String> messageData) {\n        val deviceToken = principal.getSingleValuedAttribute(properties.getRegistrationTokenAttributeName(), String.class);\n        val payload = new SimpleApnsPayloadBuilder()\n            .setAlertTitle(messageData.get(\"title\"))\n            .setAlertBody(messageData.get(\"message\"))\n            .build();\n\n        val pushNotification = new SimpleApnsPushNotification(deviceToken, properties.getTopic(), payload);\n        LOGGER.trace(\"Sending push notification to [{}] with payload [{}]\", principal, pushNotification);\n\n        apnsClient.sendNotification(pushNotification)\n            .whenComplete((response, cause) -> {\n                if (response != null) {\n                    if (response.isAccepted()) {\n                        LOGGER.debug(\"Notification [{}] sent to [{}] is accepted successfully\", pushNotification, principal.getId());\n                    } else {\n                        LOGGER.warn(\"Notification [{}] sent to [{}] rejected with error: [{}]\",\n                            pushNotification, principal.getId(), response.getRejectionReason().orElse(StringUtils.EMPTY));\n                    }\n                } else {\n                    LoggingUtils.error(LOGGER, cause);\n                }\n            });\n        return true;\n    }\n}\n","sourceCodeStart":28,"sourceCodeEnd":56,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-notifications-apn/src/main/java/org/apereo/cas/notifications/APNMessagingNotificationSender.java#L28-L56","documentation":"APNMessagingNotificationSender sends a push notification via the ApnsClient and inspects the async response. If Apple's APNs rejects the notification, it warns 'Notification [{}] sent to [{}] rejected with error: [{}]' with the rejection reason (e.g. BadDeviceToken, TopicDisallowed). The message was delivered to APNs but not accepted for delivery.","triggerScenarios":"apnsClient.sendNotification completes with a response where isAccepted() is false; the rejection reason from APNs (invalid device token, wrong topic/bundle id, expired token, payload issues) is logged.","commonSituations":"Stale device tokens for users who uninstalled the app, mismatched APNs topic vs the app's bundle identifier, wrong signing key/team settings, or environment mismatch (development token sent to production APNs).","solutions":["Read the rejection reason in the log and act on it (BadDeviceToken → remove/refresh the device token)","Verify the APNs topic matches the iOS app bundle id and the signing key/team configuration","Ensure device tokens are current and re-registered by the app","Check you are using the correct APNs environment (development vs production) endpoint/credentials"],"exampleFix":"// before\ncas.notifications.apn.topic=com.old.bundle\n// after\ncas.notifications.apn.topic=com.example.correctbundle","handlingStrategy":"try-catch","validationCode":"// pre-send sanity checks\nif (!StringUtils.hasText(deviceToken) || deviceToken.length() < 32) return;\nif (!StringUtils.hasText(apnsProperties.getTopic())) throw new IllegalStateException(\"APNs topic required\");","typeGuard":null,"tryCatchPattern":"apnsClient.sendNotification(n).whenComplete((resp, cause) -> {\n    if (cause != null) { LOGGER.error(\"APNs send failed\", cause); }\n    else if (!resp.isAccepted()) { LOGGER.warn(\"APNs rejected: {}\", resp.getRejectionReason()); }\n});","preventionTips":["Purge device tokens after BadDeviceToken rejections","Keep topic aligned with the app bundle id","Use correct environment keys (dev vs prod)","Re-register tokens on app updates"],"tags":["apns","push-notification","ios"],"backgroundTag":"api-error-response","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}