Skip to content

Add error handling to UIImage with contentsOfFile constructor#338

Merged
marcprux merged 2 commits intoskiptools:mainfrom
GavynHolt:fix/ui-image-error-handling
Feb 24, 2026
Merged

Add error handling to UIImage with contentsOfFile constructor#338
marcprux merged 2 commits intoskiptools:mainfrom
GavynHolt:fix/ui-image-error-handling

Conversation

@GavynHolt
Copy link
Contributor

@GavynHolt GavynHolt commented Feb 24, 2026

Thank you for contributing to the Skip project! Please review the contribution guide at https://skip.dev/docs/contributing/ for advice and guidance on making high-quality PRs.

Use this space to describe your change and add any labels (bug, enhancement, documentation, etc.) to help categorize your contribution.

Skip Pull Request Checklist:

  • REQUIRED: I have signed the Contributor Agreement
  • REQUIRED: I have tested my change locally with swift test
  • OPTIONAL: I have tested my change on an iOS simulator or device
  • OPTIONAL: I have tested my change on an Android emulator or device
  • REQUIRED: I have checked whether this change requires a corresponding update in the Skip Fuse UI repository (link related PR if applicable)
  • OPTIONAL: I have added an example of any UI changes in the Showcase sample app

  • AI was used to generate or assist with generating this PR. Please specify below how you used AI to help you, and what steps you have taken to manually verify the changes.

@cla-bot cla-bot bot added the cla-signed label Feb 24, 2026
@GavynHolt
Copy link
Contributor Author

This change is inspired due to a few crashes we are experiencing on the Android side with ImageDecoder:

Exception android.graphics.ImageDecoder$DecodeException: Input was incomplete.
  at android.graphics.ImageDecoder.onPartialImage (ImageDecoder.java:2091)
  at android.graphics.ImageDecoder.nDecodeBitmap
  at android.graphics.ImageDecoder.decodeBitmapInternal (ImageDecoder.java:1676)
  at android.graphics.ImageDecoder.decodeBitmapImpl (ImageDecoder.java:1865)
  at android.graphics.ImageDecoder.decodeBitmap (ImageDecoder.java:1981)
  at skip.ui.UIImage.<init> (UIImage.kt:90)
  at rspndr.guard.MediaService.uploadInvestigationImage$RspndrGuard_release (MediaService.kt:118)
  at rspndr.guard.CacheAwareInvestigationAsyncImageViewModel.uploadImage$RspndrGuard_release (CacheAwareInvestigationAsyncImageViewModel.kt:47)
  at rspndr.guard.CacheAwareInvestigationAsyncImage.body$lambda$0$1$0$0$0$0$0$0$0$0$0$0 (CacheAwareInvestigationAsyncImage.kt:94)
  at rspndr.guard.CacheAwareInvestigationAsyncImage.$r8$lambda$bh31IT3akZKEZGu7t935NN2sWBo (Unknown Source)
  at rspndr.guard.CacheAwareInvestigationAsyncImage$$ExternalSyntheticLambda5.invoke (D8$$SyntheticClass)
  at skip.ui.View.onAppear$lambda$0$1$0 (View.kt:2785)
  at skip.ui.View.$r8$lambda$JXb_wpKTOrtvn0ApZWxhfZ5k-qQ (Unknown Source)
  at skip.ui.View$$ExternalSyntheticLambda147.invoke (D8$$SyntheticClass)
  at androidx.compose.runtime.internal.RememberEventDispatcher.dispatchSideEffects (RememberEventDispatcher.kt:263)
  at androidx.compose.runtime.CompositionImpl.applyChangesInLocked (Composition.kt:1134)
  at androidx.compose.runtime.CompositionImpl.applyChanges (Composition.kt:1160)
  at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2.invokeSuspend$lambda$2 (Recomposer.kt:716)
  at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2.$r8$lambda$sdKIQuFT6MpOW8QdHT9yWSawFoM (Unknown Source)
  at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$$ExternalSyntheticLambda0.invoke (D8$$SyntheticClass)
  at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame (AndroidUiFrameClock.android.kt:39)
  at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch (AndroidUiDispatcher.android.kt:108)
  at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch (AndroidUiDispatcher.android.kt:41)
  at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame (AndroidUiDispatcher.android.kt:69)
  at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1899)
  at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1910)
  at android.view.Choreographer.doCallbacks (Choreographer.java:1367)
  at android.view.Choreographer.doFrame (Choreographer.java:1282)
  at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1870)
  at android.os.Handler.handleCallback (Handler.java:995)
  at android.os.Handler.dispatchMessage (Handler.java:103)
  at android.os.Looper.loopOnce (Looper.java:273)
  at android.os.Looper.loop (Looper.java:363)
  at android.app.ActivityThread.main (ActivityThread.java:10060)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:632)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:975)

@marcprux
Copy link
Member

Can you add a call to Log.w(message, exception) when catching the exception so there is some possibility of debugging the issue when it occurs?

@GavynHolt
Copy link
Contributor Author

Good idea, done.

@marcprux
Copy link
Member

Thanks!

@marcprux marcprux merged commit b0321af into skiptools:main Feb 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants