I’m getting bunch of weird looking crashes when I ...
# compose
j
I’m getting bunch of weird looking crashes when I use
ComposeView
within my application. I’ve dug trough all the sources and still cannot find the cause od the problem. TLDR version of it is that I have a list with error view on top of it that contains “refresh” button. Clicking it with my internet off (so that the view will appear) makes my app crash with bunch of compose related logs that do not point in any direction such as:
Copy code
java.lang.ArrayIndexOutOfBoundsException: length=3; index=3 -> ViewGroup
java.lang.IllegalArgumentException: Failed requirement -> androidx.compose.ui.node.MeasureAndLayoutDelegate
java.lang.IllegalArgumentException: Failed requirement -> androidx.compose.ui.platform.AndroidComposeView.notifyLayerIsDirty
java.lang.IllegalStateException: Underflow in restore - more restores than saves

Exception Type: Unknown (SIGSEGV)
What is important to mention is that it only happens on RELEASE version of the App. I’ve dissected my app and trying to reproduce the issue on fresh repo but I wasn’t able to, yet. No such problems when I switch to
ComponentActivity
instead of
Fragment
with
ComposeView
as its only view. I don’t have unusual amount of recompositions either - around 2 for state. Would appreciate any kind of help, guidance, ideas what might be the source of my problem.
z
What version of compose are you using? Which versions of android and devices are you seeing this on?
j
@Zach Klippenstein (he/him) [MOD]
Copy code
compose_ui_version = "1.3.0-beta03"
compose_lifecycle_version = "2.6.0-alpha02"
But I’ve tested it on previous version too - started on 1.2 and then jumped to 1.3 with hope that it’s going to solve this problem
small update - I was able to crash it also when using
ComponentActivity
z
And you get the same crash on 1.2?
j
yes
I’ve made one unusual test that makes the app not crash - normally when there is no internet I return
NoInternetException
(its a domain simplification for UnknownHostException, SocketTimeoutException, ConnectException, NoRouteToHostException) so I’ve swapped my repository implementation of list fetch to always return
throw NoInternetException
on the API calls. As it turns out the app does not crash.
z
Are you returning the exception or throwing it? Where are you throwing it from, is it inside some compose-managed code? What type of exception does cause the crash, what type of exception is
NoInternetException
?
j
Im throwing exception. It’s all within suspended function and it’s getting cought and handled. Stack is quite simple: retrofit, coroutines, stateflow. Call is coming back from repository -> usecase -> viewmodel -> stateflow. Only part that is touching compose is
StateFlow
connected via
collectAsStateWithLifecycle
. As I’ve mentioned
NoInternetException
is just a domain wrapper for some of the Exceptions thrown when offline.
Copy code
override suspend fun getSales(
        type: String,
        limit: Int,
        offset: Int,
    ): Page<SalesProduct> = 
        throw NoInternetException()
that is the fake call that is not triggering crashes within compose
z
What type of exception is it though? What’s the parent class?
j
Copy code
class NoInternetException : DomainException(null)

abstract class DomainException(override val message: String?) : RuntimeException()
This is parent so lowest is RuntimeException
One more error that is being thrown
Copy code
java.lang.IllegalStateException: Recording currently in progress - missing #endRecording() call?
z
My guess is that the exception is getting caught somewhere it should be getting rethrown, which leaves the runtime in an invalid state trying to continue running. Since it depends on the exception type, maybe there’s some try/catch handling different exception types differently somewhere? But idk if this would be in your app code or compose itself.
If that doesn’t sound like anything you’re doing in your code, please file a bug
j
i do call my API in method below
Copy code
inline fun <R> runSuspendCatching(block: () -> R): Result<R> {
    return try {
        Result.success(block())
    } catch (cancel: CancellationException) {
        throw cancel
    } catch (throwable: Throwable) {
        Result.failure(throwable)
    }
}
But the whole point of it is to rethrow CancellationException
z
What do you end up doing with that returned Result if it’s a failure?
j
Copy code
.map { pageInfo ->
   runSuspendCatching {
      useCase()
   }.getOrElse { PageResult.Error(it) }
  }.onEach { .. }
so if its Cancelation we let it brake our chain but if its not we handle it
z
That should be running anywhere in layout though if it’s suspending… hm I’m not sure how this could be breaking. I don’t suppose this code is open source so we could play with it ourselves?
j
I wish I could but unfortunately its not
z
Please file a bug anyway
j
will do
what I’ve noticed that all the exceptions seems to origin from the same spot
MutableStateSnapshot
and
View.updateDisplayListIfDirty
@Zach Klippenstein (he/him) [MOD] it turn out it was a mistake on our end - we filled out the main thread with logs to Sentry. Case closed. They changed the way they send events back at the same time we implemented Compose in our app and since logs mainly pointed at Compose that was in our opinion the main culprit.
z
Haha phew 😅
j
@Zach Klippenstein (he/him) [MOD] one thing might be a lesson to compose or an upcoming improvement - right now compose is quite delicate where it comes to main thread or file operations and crashes before your main culprit. In the long run it might be a very painful problem - like it was for me. But as of now I don’t have a solution to this problem.
z
I still don’t understand exactly what the problem was here. I am struggling to imagine how to get the layout system to crash by reading a file.
j
Filling up the MainThread - just Sentry things
r
@Jakub Wiśniewski hey, roman from sentry here. Could you pinpoint the exact version of Sentry you’re using? I don’t think we had any changes in our events pipeline recently. Otherwise it’s worth filing a bug, maybe it has to do something with coroutines which our exception handling fails to properly handle.
j
@romtsn issue was fixed in latest version and after update to 6.6.0 the issue had no longer occured
🎉 1
a
What library version do you mean that needs to be updated? I also got the same error
@Jakub Wiśniewski
im using sentry with bom: io.sentrysentry bom6.17.0
r
this is likely the release you're looking for https://github.com/getsentry/sentry-java/releases/tag/6.19.1
j
In my case that was Sentry - but this error more of a general case type of error.
As I’ve written above - once we switched to 6.6.0 problem stopped
a
ohhh i see, will try to update the sentry version. thanks a lot guys @Jakub Wiśniewski @romtsn 🙏 thank you color
419 Views