Rich notification image previews broken in v5.x — iOS app update? confirmed root cause?

Symptom: Text-only push notifications work. Image thumbnails in the notification never load — on any current iPhone 15 iOS 26, or 4th gen iPad Pro. regardless of network setup, certs, or server config. Interestingly, some older devices/older app installs do still get the image preview, which turned out to be the key clue.first gen iPad Pro, low version iOS app.

The iOS app registers for notifications with a GET request that includes a 64-bit reference number (ref=<64-bit value>) identifying that specific registration. When a motion event fires, the server is supposed to send that same ref back in the push payload so the notification extension can match the incoming push to a pending registration, then fetch the image using the connection info tied to that match.

On registration, the app sends a 64-bit reference number identifying that request, e.g.:

ref (64-bit, as registered) = 0x1A2B3C4D5E6F7890

The server is supposed to echo that same value back in the push payload so the phone's notification extension can match the incoming push to the registration it made, then fetch the image using the connection info tied to that match.

What actually gets stored and pushed back is the value truncated to a 32-bit signed int — only the low 32 bits survive:

ref (as pushed back) = 0x5E6F7890

(Hex placeholder to illustrate the mechanism, not a real captured value — but the relationship is exact in every case I captured: low 32 bits preserved, high 32 bits silently dropped.) It's consistent with the value being written through a %d-style (32-bit) format specifier somewhere in the server's storage/push code, where a 64-bit-safe specifier is needed.

Why the failure is silent instead of a timeout: the extension never gets far enough to hit the network. It receives the push, tries to match the truncated value against the full ref it registered with, finds no match, and gives up in under 30ms — before ever calling out to fetch the image. The fetch isn't failing; it's never attempted.

Confirmed server-side, not device-side: registered the same phone against two server instances the same day — one running the current major version, one running the version in question. The current major version stored/pushed the full 64-bit ref intact; the other truncated it. Same device, same app build, same day, different result depending only on server version.

Confirmed not fixed by the latest point release: binary-diffed the newest 5.x build against the prior one specifically to check this. The push payload format and ref handling are byte-identical between the two — whatever else changed in that release, this wasn't touched.

Also ruled out: valid end-to-end cert chain, correct app entitlements per the actual provisioning profile, and a from-scratch reinstall with all local state wiped — identical failure on a completely fresh, freshly-licensed install.

Given that the current major version's push payload already formats this value correctly, and the fix on the older version's side would just be widening how the ref is stored/formatted rather than any kind of redesign — is this a known issue that's been triaged and just hasn't been prioritized, since it happens to nudge anyone who wants working image previews toward the paid upgrade?

I Can share the raw before/after capture if anyone wants to verify.

Comments

  • Ben
    Ben
    edited July 30

    Thanks for this thorough report - your diagnosis is exactly right.

    What happened is that in an iOS app update a few months ago we widened the notification reference from a 32-bit to a 64-bit value, as a general robustness improvement: this reduces the chance of two servers colliding on the same reference. Version 6 stores and echoes that back correctly. Version 5 stores it in a 32-bit integer, so it keeps only the low 32 bits, and the value that comes back in the push no longer matches what the app registered. The extension can't tie the push to a server, so it never gets as far as requesting the image.

    That also explains the pattern you spotted with older installs. The reference is generated once, when a server is first added, and reused from then on. Any server added before that update still has a 32-bit reference, which survives the round trip through v5 intact. A fresh install, or re-adding the server, mints a 64-bit one and breaks.

    To be clear, this was not intentional and there's no upgrade nudge here, it's an improvement designed for v6, which just happens to break in v5 because this older software has been discontinued for a while now and we no longer test with it.

    We've now fixed this in our iOS app codebase, so when the next version of the app is released, this will just start working again.

  • Thanks Ben! Man, you are always so on top of it! Your hard work and attention to all of us doesn’t go unnoticed. Cheers.

  • Many thanks, that's much appreciated!