fix(ios): reject the promise instead of raising NSException in image compression#411
Draft
jayeshbjain wants to merge 1 commit into
Draft
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The iOS image-compression path raises
NSExceptionon several failure conditions (unsupported_value×2,file_error,drawing_error). An NSException raised inside a TurboModule invocation is not catchable from JavaScript and aborts the whole app (SIGABRT) — Swiftdo/catchcan't intercept ObjC exceptions either, so the existingcatchinImageMain.image_compressnever fires.This is not theoretical: we hit it in production. iOS relocated our app's data container during an OS update (Apple documents that container paths may change between updates), which invalidated a stored absolute file path.
Image.compresson that dead path →loadImagereturns nil →NSException("unsupported_value")→ the app died 991ms after every launch, a permanent boot loop for the user (crash log frames:ImageCompressor.manualCompressHandler←getAbsoluteImagePath←Compressor.image_compress).Fix
Convert all four raise sites to Swift
throw NSError(...)and propagate:manualCompressHandler/autoCompressHandler/manualCompress/writeImage/manualResizebecomethrowsImageMain.image_compress: the base64 branch's errors flow to the existing outercatch; the URI branch runs insidegetAbsoluteImagePath's escaping closure (outside the outerdo/catch), so it gets its owndo/catchthat callsrejectunsupported_value/"Unsupported value type."etc.), so callers that match on the message keep working — they now receive a promise rejection instead of a crashAlso removed in passing:
free(&targetData)before thedrawing_errorraise —targetDatais a Swift-managed[UInt8]array, so callingfree()on its address was undefined behavior; the array is released by ARC.Behavior change
None on success paths. On the four failure conditions the JS promise rejects (with the same error name/message) instead of the process aborting.
Testing
1.19.2(same change rebased ontomainhere).Image.compress('file:///path/that/does/not/exist.jpg', { compressionMethod: 'manual' })on iOS — before: SIGABRT; after: promise rejection.Marked as draft for maintainer review of error-domain conventions.
🤖 Generated with Claude Code