Skip to content

[Due for payment 2026-09-28] [Sentry: APP-KDN] iOS HybridApp native crash — RCTBlobManager slices a blob past its data length #100843

Description

@mountiny

Sentry

Impact (snapshot at filing, 2026-09-10)

Sentry ID Users (last 14d) Users (total since first seen) Events First seen
APP-KDN 5 6 19 2026-08-25
  • Last seen: 2026-09-10 (ongoing)
  • Platform: iOS HybridApp (com.expensify.expensifylite)
  • App version(s): 9.4.68-1, 9.4.70-0, 9.4.71-0, 9.4.72-0, 9.4.73-2, 9.4.75-0 — present on every recent build
  • Mechanism: nsexception, level fatal — this is a hard native crash, not a caught error
  • Thread: crashes on a _dispatch_workloop_worker_thread, off the main thread
  • session.uptime_bucket: 0-30s on the sampled event, so it fires early in the session
  • Device on the sampled event: iPhone 12 mini, iOS 16.7, lowMemoryThreat: true

Error

NSRangeException: *** -[NSConcreteMutableData subdataWithRange:]: range {0, 321} exceeds data length 318

Stack trace (top frames)

__exceptionPreprocess
objc_exception_throw
-[NSData(NSData) subdataWithRange:]
-[RCTBlobManager resolve:offset:size:] (RCTBlobManager.mm:115)
-[RCTBlobManager resolve:] (RCTBlobManager.mm:101)
-[RCTBlobManager createFromParts:withId:] (RCTBlobManager.mm:199)
facebook::react::ObjCTurboModule::performVoidMethodInvocation (RCTTurboModule.mm:461)
_dispatch_call_block_and_release

Suspected cause

RCTBlobManager stores blob data in a dictionary keyed by blob ID and slices it on demand. resolve:offset:size: calls subdataWithRange: using the offset and size recorded in the blob descriptor, without checking them against the length of the data actually held.

The numbers in the message say the descriptor and the stored data disagree by 3 bytes: the JS side asks for 321 bytes but only 318 are present. Two plausible sources:

  1. The stored NSMutableData was truncated or partially written, so the recorded size is stale.
  2. A byte-length versus character-length mismatch when a string is turned into a blob — a multi-byte UTF-8 sequence counted as characters would produce exactly this kind of small shortfall.

createFromParts:withId: is on the stack, so the crash happens while assembling a multi-part blob, which is what new Blob([...]) and FormData uploads go through. The most likely trigger in App is an attachment or receipt upload.

Because this is an NSRangeException on a background dispatch queue, there is no JS frame to catch it and the app terminates.

Reproduction

Unknown as an exact click path — 19 events across 6 users, so it is timing or content dependent rather than a deterministic screen. Starting points:

  1. On iOS HybridApp, upload a receipt or attachment shortly after launch, while the app is still hydrating.
  2. Try content that is not plain ASCII — a file name or text part containing multi-byte UTF-8 characters.
  3. Watch for the crash under memory pressure; the sampled event had lowMemoryThreat: true.

Once reproduced, the fix is to clamp the range in resolve:offset:size: against the real data length and log rather than throw when the descriptor disagrees. That belongs upstream in react-native, so the immediate options are a patch file or a version bump once fixed upstream.

Related

Issue OwnerCurrent Issue Owner: @mallenexpensify

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.ExternalAdded to denote the issue can be worked on by a contributorWeeklyKSv2

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions