stuck notification badge with element x on ios #1966

Open
opened 2026-07-12 02:15:23 +00:00 by numinara · 12 comments

when element x on ios gets a notification, the notification badge goes to 1, and then even after the message is read, and every client of mine (element x, element classic, fluffychat, iamb; all of them verified) removes the notification and/or says there are no unread messages, the badge still stays. only re-logging seems to be able to clear it.

my homeserver (still running on 0.5.10 due to nixpkgs being slow to update, but this has been going on for a long time) sends 0 for unread notifications and highlights on both the classic and simplified sliding sync endpoints.

all my pushers seem to be registered with format: event_id_only, and iirc element x doesn't do any local badge calculation, so the badge seems to depend entirely on the unread count in the last notify event.

i'm guessing that the server doesn't properly send events to reset the unread count to 0; since every new proper notification has at least 1 as the unread count, if that event is missing, the badge will never clear (and if my memory holds, this badge-update notify is exactly what synapse sends when the read receipts change the counts, and i haven't heard of this issue there).
just speculating though!

happy to grab any logs or help however i can!

when element x on ios gets a notification, the notification badge goes to 1, and then even after the message is read, and every client of mine (element x, element classic, fluffychat, iamb; all of them verified) removes the notification and/or says there are no unread messages, the badge still stays. only re-logging seems to be able to clear it. my homeserver (still running on 0.5.10 due to nixpkgs being slow to update, but this has been going on for a long time) sends 0 for unread notifications and highlights on both the classic and simplified sliding sync endpoints. all my pushers seem to be registered with `format: event_id_only`, and iirc element x doesn't do any local badge calculation, so the badge seems to depend entirely on the unread count in the last notify event. i'm guessing that the server doesn't properly send events to reset the unread count to 0; since every new proper notification has at least 1 as the unread count, if that event is missing, the badge will never clear (and if my memory holds, this badge-update notify is exactly what synapse sends when the read receipts change the counts, and i haven't heard of this issue there). just speculating though! happy to grab any logs or help however i can!
Owner

this appears to be an Element X [iOS] bug, as I have the same issue on my phone. Actually, I have a notification badge stuck at 4, not 1, but the second instance of Element X is itself stuck on 1. Those two apps are logged into Synapse, so I can only assume it's a bug with the app.

this appears to be an Element X [iOS] bug, as I have the same issue on my phone. Actually, I have a notification badge stuck at 4, not 1, but the second instance of Element X is itself stuck on 1. Those two apps are logged into Synapse, so I can only assume it's a bug with the app.
Author

oh, then my memory didn't hold!

awesome on the extra data, and will bombard their trackers with this instead.

should i close this issue or is it useful in case it turns out to be partially server-side or such?

oh, then my memory didn't hold! awesome on the extra data, and will bombard their trackers with this instead. should i close this issue or is it useful in case it turns out to be partially server-side or such?
Owner

We can keep it open in case other people have the same problem too, we're generally aware of some obscure bug that causes notification counts to get stuck, so my assumption may be based on coincidence

We can keep it open in case other people have the same problem too, we're generally aware of some obscure bug that causes notification counts to get stuck, so my assumption may be based on coincidence
Author

i've checked the element x issue trackers too, and there are multiple closed issues that were supposedly fixed, but there's an open one describing this exact problem, and someone said it happens with fluffychat too (although personally i haven't seen this), so it might be a server-side thing, made server-agnostic by the spec itself being bad, idk. leaving open as you suggested either way

i've checked the element x issue trackers too, and there are multiple closed issues that were supposedly fixed, but there's an [open one](https://github.com/element-hq/element-x-ios/issues/3151) describing this exact problem, and someone said it happens with fluffychat too (although personally i haven't seen this), so it might be a server-side thing, made server-agnostic by the spec itself being bad, idk. leaving open as you suggested either way
Owner

https://github.com/element-hq/element-x-ios/issues/3151#issuecomment-4891570750 this might be interesting. I'll have to take a look and see where we're incrementing the count

https://github.com/element-hq/element-x-ios/issues/3151#issuecomment-4891570750 this might be interesting. I'll have to take a look and see where we're incrementing the count
Author

okay yeah this seems to be happening with fluffychat too. i joined the continuwuity support channel, got 91 notifs while away, and now both apps are stuck on that number

okay yeah this seems to be happening with fluffychat too. i joined the continuwuity support channel, got 91 notifs while away, and now both apps are stuck on that number

I have the same problem, which is why I'm currently using Element Classic for iOS again.

I have the same problem, which is why I'm currently using Element Classic for iOS again.
Author

i've been doing some testing. if i send a payload like this to the matrix notification gateway (nushell syntax):

{
  notification: {
    counts: { unread: 0 },
    devices: [
      {
        app_id: "io.element.elementx.ios.prod",
        pushkey: "REDACTED",
        data: {
          format: "event_id_only",
          default_payload: {
            aps: {
              alert: { loc-args: [], loc-key: "Notification" },
              mutable-content: 1
            },
            pusher_notification_client_identifier: "REDACTED"
          }
        }
      }
    ]
  }
} | to json | curl -s -X POST -H "Content-Type: application/json" -d @- https://matrix.org/_matrix/push/v1/notify

where the REDACTED fields should be filled from the pushers list: curl -s -H "Authorization: Bearer <token>" https://<homeserver>/_matrix/client/v3/pushers

then matrix.org responds {"rejected": []} and then sets the notification badge to whatever i set up top (and makes it go away with 0)

checking the source, it seems like the only code path that queues a push is an event append (src/service/rooms/timeline/append.rs -> send_pdu_push), whereas synapse explicitly sends unread count updates on read receipts (receipts.py -> pusherpool.on_new_receipts -> httppusher._update_badge -> _send_badge)

so the badge really is just stuck on whatever the last notification event said (which will always have >=1), and this would be solved by continuwuity sending a similar unread count update (not just at 0, but any time something is read) to the push gateway when a client produces a read receipt (the spec already allows counts-only notifs so no need for an msc). there still are inconsistencies in the badge count with synapse, which then likely stem from server-side counting issues instead.

another, related issue is that the badge count is currently derived from the unread count of only the room where the notification originates from, rather than a global count. this means that if i have two rooms, one with 4 unread messages, and another with 1, then if i get a message to the latter, the badge says 2 rather than 6. this can be fixed by sending the global sum (or doing the synapse default of reporting the number of rooms with unreads, rather than the unread count itself).

fix sketch: a counts-only send_badge_notice in the pusher service (similarly to send_notice, but without the event fields), a global unread computation to fix the secondary issue, hooks at the reset_notification_counts call sites (which should cover m.read, m.read.private, read markers, and the sender-side reset on send), some caching so the same badge number isn't re-pushed needlessly, and skipping pushers for clients that set disable_badge_count.

happy to pr this if the approach sounds right!

i've been doing some testing. if i send a payload like this to the matrix notification gateway (nushell syntax): ``` nu { notification: { counts: { unread: 0 }, devices: [ { app_id: "io.element.elementx.ios.prod", pushkey: "REDACTED", data: { format: "event_id_only", default_payload: { aps: { alert: { loc-args: [], loc-key: "Notification" }, mutable-content: 1 }, pusher_notification_client_identifier: "REDACTED" } } } ] } } | to json | curl -s -X POST -H "Content-Type: application/json" -d @- https://matrix.org/_matrix/push/v1/notify ``` where the `REDACTED` fields should be filled from the pushers list: `curl -s -H "Authorization: Bearer <token>" https://<homeserver>/_matrix/client/v3/pushers` then matrix.org responds `{"rejected": []}` and then sets the notification badge to whatever i set up top (and makes it go away with 0) checking the source, it seems like the only code path that queues a push is an event append (`src/service/rooms/timeline/append.rs -> send_pdu_push`), whereas synapse explicitly sends unread count updates on read receipts (`receipts.py -> pusherpool.on_new_receipts -> httppusher._update_badge -> _send_badge`) so the badge really is just stuck on whatever the last notification event said (which will always have >=1), and this would be solved by continuwuity sending a similar unread count update (not just at 0, but any time something is read) to the push gateway when a client produces a read receipt (the spec already allows counts-only notifs so no need for an msc). there still are inconsistencies in the badge count with synapse, which then likely stem from server-side counting issues instead. another, related issue is that the badge count is currently derived from the unread count of only the room where the notification originates from, rather than a global count. this means that if i have two rooms, one with 4 unread messages, and another with 1, then if i get a message to the latter, the badge says 2 rather than 6. this can be fixed by sending the global sum (or doing the synapse default of reporting the number of rooms with unreads, rather than the unread count itself). fix sketch: a counts-only send_badge_notice in the pusher service (similarly to send_notice, but without the event fields), a global unread computation to fix the secondary issue, hooks at the reset_notification_counts call sites (which should cover m.read, m.read.private, read markers, and the sender-side reset on send), some caching so the same badge number isn't re-pushed needlessly, and skipping pushers for clients that set disable_badge_count. happy to pr this if the approach sounds right!
Owner

can everybody on this bug retry on main ? I am suspicious this fixes it: #2037

can everybody on this bug retry on main ? I am suspicious this fixes it: https://forgejo.ellis.link/continuwuation/continuwuity/pulls/2037
Author

nice one!

that pr seems to fix cases where the sent count is wrong outright. the issue encountered here is that the badge isn't updated outside of new message notifications, causing it to get stuck. so the issue here isn't (just) the count being wrong, it's that it isn't being sent out on read receipts.

i'm not in a situation where i can easily test main. if someone can do that though, i recommend testing by reading everything on a client and seeing if that properly clears the badge on another

nice one! that pr seems to fix cases where the sent count is wrong outright. the issue encountered here is that the badge isn't updated outside of new message notifications, causing it to get stuck. so the issue here isn't (just) the count being wrong, it's that it isn't being sent out on read receipts. i'm not in a situation where i can easily test main. if someone can do that though, i recommend testing by reading everything on a client and seeing if that properly clears the badge on another

I did a bit of testing on main and found that #2037 fixed the number shown in the badge being inaccurate. However the badge still only updates when a new notification is received, causing it to be "stuck".

I tested this by first sending myself 3 messages from another account, which caused the badge to correctly update to 3. After opening the app, reading the messages and exiting the app, the badge still stays at 3. If i now send myself another message and thus get a notification, the badge changes from 3 to 1, indicating that the count itself is now actually correct but the badge is only updating on new notifications.

The same also happens if i read the 3 original messages in another client (Element X badge shows 3 and updates to 1 if i receive a message after having read the original messages in another client)

I couldnt do this test with FluffyChat yet, but i can confirm that i did have the stuck badge problem on FluffyChat as well.

I did a bit of testing on main and found that [#2037](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/2037) fixed the number shown in the badge being inaccurate. However the badge still only updates when a new notification is received, causing it to be "stuck". I tested this by first sending myself 3 messages from another account, which caused the badge to correctly update to 3. After opening the app, reading the messages and exiting the app, the badge still stays at 3. If i now send myself another message and thus get a notification, the badge changes from 3 to 1, indicating that the count itself is now actually correct but the badge is only updating on new notifications. The same also happens if i read the 3 original messages in another client (Element X badge shows 3 and updates to 1 if i receive a message after having read the original messages in another client) I couldnt do this test with FluffyChat yet, but i can confirm that i did have the stuck badge problem on FluffyChat as well.
Author

okay wonderful! i mean it's bad because the bug is still there but this is great evidence for the exact thing i described
@nex (or anyone actually familiar with continuwuity internals) could you check out the fix sketch above? if it seems sane, i'll start working on a pr

okay wonderful! i mean it's bad because the bug is still there but this is great evidence for the exact thing i described @nex (or anyone actually familiar with continuwuity internals) could you check out the fix sketch above? if it seems sane, i'll start working on a pr
Sign in to join this conversation.
No milestone
No project
No assignees
5 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
continuwuation/continuwuity#1966
No description provided.