Skip to main content
Solved

Paywalls V2 icon assets return 403 (S3 AccessDenied) from icons.pawwalls.com — floods error monitoring for all users

  • July 3, 2026
  • 5 replies
  • 43 views

Forum|alt.badge.img+3

Our Paywalls V2 paywall uses three icon components (checkmark, X, and lock). On every paywall render, the SDK tries to download them and gets HTTP 403 — for essentially every user, on every app version. The paywall itself works (icons presumably fall back / don't render), but each render produces 3 failed requests, which floods our error monitoring (New Relic records them as MobileRequestError — we see ~1,150/week).

Environment

- react-native-purchases / react-native-purchases-ui 10.4.1 (issue was also present on older versions)
- Expo SDK 56, Android (okhttp/4.12.0 does the fetch, so this is the native Android paywall engine)
- Paywalls V2, icons selected in the dashboard paywall editor

Failing URLs

https://icons.pawwalls.com/lock-code.webp
https://icons.pawwalls.com/x.webp
https://icons.pawwalls.com/check.webp

Reproduction — fails from anywhere, not just devices:

curl -i 'https://icons.pawwalls.com/check.webp' -H 'user-agent: okhttp/4.12.0'

Response:

HTTP/2 403
content-type: application/xml
server: AmazonS3
x-cache: Error from cloudfront

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message>
<RequestId>GZH30QRDG7MRYC21</RequestId></Error>

So this is not a client/SDK bug per se: CloudFront is returning an S3 AccessDenied, meaning the objects are missing or private in the origin bucket, while published paywall configs still reference these URLs. (S3 returns 403 instead of 404 when the requester lacks list permission, so these may simply be deleted objects.)

Questions

1. Can you restore these icon assets on the CDN (or fix the bucket policy)? That would immediately fix all published paywalls referencing them.
2. If these icons are deprecated, why does the paywall editor still produce configs referencing them — and is our only option to manually re-select every icon component and re-publish?
3. Is there a recommended way to stop the SDK from retrying known-dead assets on every render? The repeated failed requests pollute APM/error tooling that auto-instruments HTTP.

Happy to provide our app ID / paywall ID privately if useful.

Best answer by Tarek

Hey ​@florind,

 

I'm Tarek from Developer Support, thanks a lot for reaching out, and for the exceptional investigation.

 

I checked and it seems like you're spot on.

 

To confirm your own conclusions on the original questions: there's nothing to restore on the CDN, the assets are all present and public under /icons/, and your published paywall config is correct. Re-selecting the icons or re-publishing wouldn't change anything, so no action is needed on your side.

 

On silencing the failed requests in the meantime: there's currently no SDK option to disable the image pre-download, it's enabled automatically whenever the paywalls UI module is present. Until the fix ships, the practical option is to filter these out in New Relic, for example a drop rule or alert filter on the icons.pawwalls.com domain. Functionally you're not losing anything today, the pre-warm has simply never worked, and icons are fetched normally at render time.

 

I've flagged your GitHub issue (thank you for that!) to our SDK team, and your suggested one-line fix matches what the render path already does. I suggest you keep an eye on the issue for the release it lands in. I can also follow up here as well once it ships if you'd like me to.

 

Let me know if that makes sense and if there's anything else I can help with!

 

Have an excellent day.

 

Best regards,

5 replies

Forum|alt.badge.img+3
  • Author
  • New Member
  • July 3, 2026

Update — root cause found, and it IS a client SDK bug after all.

The icons are not missing from the CDN — they live under an /icons/ path prefix, and the Android SDK drops that prefix when building the pre-download URLs:

$ curl -so /dev/null -w "%{http_code}\n" https://icons.pawwalls.com/check.webp        # 403 — URL the SDK builds
$ curl -so /dev/null -w "%{http_code}\n" https://icons.pawwalls.com/icons/check.webp  # 200 — correct URL

The offerings response correctly serves "base_url": "https://icons.pawwalls.com/icons", but PaywallComponentsImagePreDownloader in purchases-android builds the icon URL with Uri.parse(baseUrl).buildUpon().path(formats.webp) — and Uri.Builder.path() replaces the whole path instead of appending, silently discarding /icons.

This also explains the details that didn't add up:

- It happens for ~every user without opening the paywall, because the pre-downloader runs on app start after the offerings fetch.
- The paywall renders fine, because the render path (IconComponentState) concatenates the URL correctly — only the pre-warm is broken (so icons are never actually cached ahead of time).
- iOS is unaffected because its cache warmer uses appendingPathComponent, which appends correctly.

Filed with full analysis, debug logs, and a suggested one-line fix: (https://github.com/RevenueCat/purchases-android/issues/3712)

So questions 1 and 2 from my original post are moot — nothing to restore on the CDN, and re-selecting icons wouldn't help since every icon goes through the same broken code path. The fix needs to ship in purchases-android.


Tarek
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • Answer
  • July 3, 2026

Hey ​@florind,

 

I'm Tarek from Developer Support, thanks a lot for reaching out, and for the exceptional investigation.

 

I checked and it seems like you're spot on.

 

To confirm your own conclusions on the original questions: there's nothing to restore on the CDN, the assets are all present and public under /icons/, and your published paywall config is correct. Re-selecting the icons or re-publishing wouldn't change anything, so no action is needed on your side.

 

On silencing the failed requests in the meantime: there's currently no SDK option to disable the image pre-download, it's enabled automatically whenever the paywalls UI module is present. Until the fix ships, the practical option is to filter these out in New Relic, for example a drop rule or alert filter on the icons.pawwalls.com domain. Functionally you're not losing anything today, the pre-warm has simply never worked, and icons are fetched normally at render time.

 

I've flagged your GitHub issue (thank you for that!) to our SDK team, and your suggested one-line fix matches what the render path already does. I suggest you keep an eye on the issue for the release it lands in. I can also follow up here as well once it ships if you'd like me to.

 

Let me know if that makes sense and if there's anything else I can help with!

 

Have an excellent day.

 

Best regards,


Forum|alt.badge.img+3
  • Author
  • New Member
  • July 3, 2026

Hey ​@Tarek,

Thanks for answer and trying to help me.

We will ignore the failed requests in our NewRelic account and wait for the issue to be resolved on Github.

Have a wonderful day,

Florin,

Angry Software 

 


Tarek
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • July 6, 2026

Hey ​@florind,

 

The PR has been merged, it should land in the next version of the SDK this week.

 

I'll keep you updated here.

 

Best,


Tarek
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • July 10, 2026

Hey ​@florind,

 

I'm glad to tell you that the fix is part of the latest release of the Android SDK, version 10.13.0, available here.

 

Feel free to update your dependencies, it should fix the issue.

 

Best,