Skip to content

🐛 Crash on watchOS when storing etags in UserDefaults #5912

@leoMehlig

Description

@leoMehlig

Describe the bug

Our watchOS app crashes here because RC is attempting to store too much data in UserDefaults.

We are getting these error messages:

CFPrefsPlistSource<0x1099a6480> (Domain: com.leomehlig.today.debug.watch.revenuecat.etags, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null), Contents Need Refresh: Yes): Attempting to store >= 1048576 bytes of data in CFPreferences/NSUserDefaults on this platform is invalid. This is a bug in Structured or a library it uses.
<decode: bad range for [%@] got [offs:528 len:902 within:0]>
NSUserDefaults/CFPreferences byte count limit reached for com.leomehlig.today.debug.watch.revenuecat.etags

And this is the stack trace:

#20	0x0000000181a295d4 in -[NSUserDefaults(NSUserDefaults) setObject:forKey:] ()
#21	0x000000010cc73f4c in closure #1 in ETagManager.storeIfPossible(_:for:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Networking/HTTPClient/ETagManager.swift:200
#22	0x000000010cc74ff8 in partial apply for closure #1 in ETagManager.storeIfPossible(_:for:) ()
#23	0x000000010cc46184 in closure #1 in SynchronizedUserDefaults.write(_:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Misc/Concurrency/SynchronizedUserDefaults.swift:35
#24	0x000000010cc461ec in partial apply for closure #1 in SynchronizedUserDefaults.write(_:) ()
#25	0x000000010cc390ac in closure #1 in Atomic.withValue<UserDefaults>(_:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Misc/Concurrency/Atomic.swift:82
#26	0x000000010cc39144 in partial apply for closure #1 in Atomic.withValue<A>(_:) ()
#27	0x000000010cc399d0 in Lock.perform<()>(_:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Misc/Concurrency/Lock.swift:44
#28	0x000000010cc388a0 in Atomic.withValue<UserDefaults>(_:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Misc/Concurrency/Atomic.swift:81
#29	0x000000010cc460f4 in SynchronizedUserDefaults.write(_:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Misc/Concurrency/SynchronizedUserDefaults.swift:34
#30	0x000000010cc72ab0 in ETagManager.storeIfPossible(_:for:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Networking/HTTPClient/ETagManager.swift:199
#31	0x000000010cc723c4 in ETagManager.httpResultFromCacheOrBackend(with:request:retried:isFallbackURLRequest:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Networking/HTTPClient/ETagManager.swift:96
#32	0x000000010cc89250 in closure #2 in HTTPClient.createVerifiedResponse(request:urlRequest:data:response:requestStartTime:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Networking/HTTPClient/HTTPClient.swift:428
#33	0x000000010cb9ea50 in Result.map<RevenueCat.VerifiedHTTPResponse<Foundation.Data?>>(_:) ()
#34	0x000000010cc888a0 in HTTPClient.createVerifiedResponse(request:urlRequest:data:response:requestStartTime:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Networking/HTTPClient/HTTPClient.swift:427
#35	0x000000010cc87df8 in HTTPClient.parse(urlResponse:request:urlRequest:data:error:requestStartTime:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Networking/HTTPClient/HTTPClient.swift:372
#36	0x000000010cc89cf4 in HTTPClient.handle(urlResponse:request:urlRequest:data:error:requestStartTime:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Networking/HTTPClient/HTTPClient.swift:465
#37	0x000000010cc8cff8 in closure #2 in HTTPClient.start(request:) at /Users/leo/Library/Developer/Xcode/DerivedData/Structured-eucdumrilarbkdhfycjshszdinhd/SourcePackages/checkouts/purchases-ios-spm/Sources/Networking/HTTPClient/HTTPClient.swift:615
#38	0x000000010cc8d130 in thunk for @escaping @callee_guaranteed @Sendable (@guaranteed Data?, @guaranteed NSURLResponse?, @guaranteed Error?) -> () ()
#39	0x0000000180ddfa30 in __40-[__NSURLSessionLocal taskForClassInfo:]_block_invoke ()
#40	0x0000000180df685c in __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke_2 ()
#41	0x0000000104e77fb8 in _dispatch_call_block_and_release ()
#42	0x0000000104e919dc in _dispatch_client_callout ()
#43	0x0000000104e80494 in _dispatch_lane_serial_drain ()
#44	0x0000000104e810f8 in _dispatch_lane_invoke ()
#45	0x0000000104e8d294 in _dispatch_root_queue_drain_deferred_wlh ()
#46	0x0000000104e8c7f0 in _dispatch_workloop_worker_thread ()
#47	0x00000001049f2b8c in _pthread_wqthread ()
Enqueued from com.apple.NSURLSession-work (Thread 6) Queue : com.apple.NSURLSession-work (serial)

This is the content that is attempted to be stored.
etag.json

Platform

watchOS

SDK version

5.49.3

SDK integration method

Swift Package Manager

StoreKit version

StoreKit 2 (default on versions >=5.0.0)

OS version

watchOS 26.1

Xcode version

Xcode 26.1

Device and/or simulator

Device

Environment

Sandbox

How widespread is the issue

100%

Debug logs

VERBOSE: Creating intermediate key with expiration '2026-01-24 00:00:00 +0000': 57fc5dbd7eca45b3c0048a49cfbe74d11b3ebc8bd44c7b9035405bf8374ea720
VERBOSE: Verifying signature 'V/xdvX7KRbPABIpJz7500Rs+vIvUTHuQNUBb+DdOpyD9TwAAWmX78ljZPdul2NHt0sBv0iDaTppOumBPLeBSDzs85r01SFN3pIh4SpDQo2tmR696qKYetMbDRvpRudWVayWzCLs5ZQepoKgCeu0Os7IxRMOM+g6UG9wA25XZNyErKKAIHRuX/qVfOhUja/1a194/ESoSRcSZUO+sM3OgM2/HjBXt08yROU0nKdvny4/uDJ8K'
Public key: '57fc5dbd7eca45b3c0048a49cfbe74d11b3ebc8bd44c7b9035405bf8374ea720'
Parameters: SignatureParameters(" +
    path: '/v1/subscribers/48223980-296A-4E59-B43F-34ED343A695E'
    message: '{"request_date":"2025-12-08T08:17:42Z","request_date_ms":1765181862590,"subscriber":{"entitlements":{},"first_seen":"2025-05-08T05:57:37Z","last_seen":"2025-10-27T11:25:38Z","management_url":null,"non_subscriptions":{},"original_app_user_id":"48223980-296A-4E59-B43F-34ED343A695E","original_application_version":null,"original_purchase_date":null,"other_purchases":{},"subscriptions":{}}}'
    headerParametersHash: 'X-Is-Sandbox:sha256:b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b'
    headers: '["X-Is-Sandbox": "true", "X-Nonce": "g0Kwjx1cqU6VCKWz", "X-Client-Bundle-ID": "com.leomehlig.today.debug.watch", "X-Observer-Mode-Enabled": "false", "X-Is-Debug-Build": "true", "X-Apple-Device-Identifier": "702BF815-0F3C-40C8-9723-D0DFA4D48AF5", "X-Is-Backgrounded": "false", "X-Platform": "watchOS", "X-Client-Version": "4.3.12", "content-type": "application/json", "X-Platform-Version": "Version 26.1 (Build 23S36)", "X-Version": "5.49.3", "X-Platform-Flavor": "native", "X-Preferred-Locales": "en_US,en_DE,de_DE", "X-StoreKit2-Enabled": "true", "X-Platform-Device": "arm64", "X-StoreKit-Version": "2", "X-Storefront": "USA", "X-Client-Build-Version": "1", "X-Retry-Count": "0", "Authorization": "Bearer appl_GarOXrlrfFuueoLaETpGIJysogV", "X-Headers-Hash": "X-Is-Sandbox:sha256:b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b"]'
    postParameterHeader: ''
    nonce: 'g0Kwjx1cqU6VCKWz'
    etag: '0bf3d739e60035e2'
    requestDate: 1765181862590
)
Salt: uzllB6mgqAJ67Q6zsjFEww==,
Payload: jPoOlBvcANuV2TchKyigCB0bl/6lXzoVI2v9WtfePxEqEkXEmVDvrDNzoDNvx4wV7dPMkTlNJynb58uP7gyfCg==,
Message: uzllB6mgqAJ67Q6zsjFEw2FwcGxfR2FyT1hybHJmRnV1ZW9MYUVUcEdJSnlzb2dWg0Kwjx1cqU6VCKWzL3YxL3N1YnNjcmliZXJzLzQ4MjIzOTgwLTI5NkEtNEU1OS1CNDNGLTM0RUQzNDNBNjk1RVgtSXMtU2FuZGJveDpzaGEyNTY6YjViZWE0MWI2YzYyM2Y3YzA5ZjFiZjI0ZGNhZTU4ZWJhYjNjMGNkZDkwYWQ5NjZiYzQzYTQ1YjQ0ODY3ZTEyYjE3NjUxODE4NjI1OTAwYmYzZDczOWU2MDAzNWUyeyJyZXF1ZXN0X2RhdGUiOiIyMDI1LTEyLTA4VDA4OjE3OjQyWiIsInJlcXVlc3RfZGF0ZV9tcyI6MTc2NTE4MTg2MjU5MCwic3Vic2NyaWJlciI6eyJlbnRpdGxlbWVudHMiOnt9LCJmaXJzdF9zZWVuIjoiMjAyNS0wNS0wOFQwNTo1NzozN1oiLCJsYXN0X3NlZW4iOiIyMDI1LTEwLTI3VDExOjI1OjM4WiIsIm1hbmFnZW1lbnRfdXJsIjpudWxsLCJub25fc3Vic2NyaXB0aW9ucyI6e30sIm9yaWdpbmFsX2FwcF91c2VyX2lkIjoiNDgyMjM5ODAtMjk2QS00RTU5LUI0M0YtMzRFRDM0M0E2OTVFIiwib3JpZ2luYWxfYXBwbGljYXRpb25fdmVyc2lvbiI6bnVsbCwib3JpZ2luYWxfcHVyY2hhc2VfZGF0ZSI6bnVsbCwib3RoZXJfcHVyY2hhc2VzIjp7fSwic3Vic2NyaXB0aW9ucyI6e319fQo=
VERBOSE: Signature passed verification
VERBOSE: Storing etag '0bf3d739e60035e2' for request to 'https://api.revenuecat.com/v1/subscribers/48223980-296A-4E59-B43F-34ED343A695E' (success)

Steps to reproduce

  1. Run app on watchOS
  2. Login user
  3. crash

Other information

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions