Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Desktop: User-friendly crash of the window when exception is thrown inside Composable (show alert to the user) #663

Closed
igordmn opened this issue May 13, 2021 · 6 comments
Assignees
Labels
desktop enhancement New feature or request
Milestone

Comments

@igordmn
Copy link
Collaborator

igordmn commented May 13, 2021

Currently if we have a java exception inside Composable function we stop the rendering loop.
And user just sees the frozen window (but with ability to close it).

Usually this kind of exception is a bug that should be fixed by the developer (IO exceptions shouldn't be thrown in Composable).

Possible solutions:

  1. close the window
  2. close the application
  3. show alert dialog (like in .NET applications)
  4. show alert dialog and close the window (or application)
  5. do nothing (like in the current implementation), provide a way to show a dialog on the any exception inside the rendering loop (currently developer can catch all exceptions in Thread.setDefaultUncaughtExceptionHandler)
@igordmn igordmn added enhancement New feature or request desktop labels May 13, 2021
@igordmn igordmn self-assigned this May 13, 2021
@lucas-ap150
Copy link

Could it be so that the window doesn't "freeze", or at least have an api to restart its event loop?

Right now if a ui exception happens, you are forced to close that window, there's no way to keep the app running on it.
You could have an app architecture where app state is still in memory, and you wanted to simply recompose the ui again after an exception (maybe to a previous state so it doesn't crash again), and show an error indicator like intellij-idea does.

But since the window freezes for good, in my app i had to hack a solution where the DefaultUncaughtExceptionHandler quickly closes the old window and opens a new one, "resuming" the app there. But it doesn't look good ui-wise (window closing-opening out of nowhere, since an exception is unexpected), and i need to manually copy the old-window's position/size/etc to the new one. It would be nicer to simply recompose in the original window instead.

I came from javafx, where an exception in ui thread simply triggers a dialog, but the event loop stays running. You can suppress the dialog and handle the exception in other ways inside your app.

@lucas-ap150
Copy link

Also i want to note that you can't close the frozen window if it is undecorated, since the manually drawn window controls are in compose code (Alt-f4 still works though)

@igordmn igordmn added this to the 1.0 milestone Nov 5, 2021
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Nov 21, 2021
Fixes JetBrains/compose-multiplatform#663

If users use Thread.currentThread().setUncaughtExceptionHandler, then now they should start application with
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Nov 21, 2021
@igordmn
Copy link
Collaborator Author

igordmn commented Nov 25, 2021

Now (1.0.0-rc3) we show a dialog on error by default, and close the window.

Users can override it via ComposeWindow.exceptionHandler or LocalWindowExceptionHandlerFactory

@igordmn igordmn closed this as completed Nov 25, 2021
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Jan 14, 2022
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Jan 18, 2022
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Jan 20, 2022
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Jan 20, 2022
@igordmn
Copy link
Collaborator Author

igordmn commented Jan 22, 2022

There is a bug in 1.0.1. Because of it we can't override LocalWindowExceptionHandlerFactory. Will be fixed in 1.0.2/1.1.

Until then, the alternative is to set it via ComposeWindow:

    Window(onCloseRequest = ::exitApplication) {
        DisposableEffect(Unit) {
            window.exceptionHandler = WindowExceptionHandler {
                
            }
            onDispose {  }
        }
    }

igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Feb 18, 2022
Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Mar 28, 2022
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Mar 30, 2022
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
eymar pushed a commit to JetBrains/compose-multiplatform-core that referenced this issue Apr 18, 2022
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
eymar pushed a commit to JetBrains/compose-multiplatform-core that referenced this issue Jun 2, 2022
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
eymar pushed a commit to JetBrains/compose-multiplatform-core that referenced this issue Jun 27, 2022
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Aug 18, 2022
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
igordmn added a commit to JetBrains/compose-multiplatform-core that referenced this issue Aug 18, 2022
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
eymar pushed a commit to JetBrains/compose-multiplatform-core that referenced this issue Oct 26, 2022
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
eymar pushed a commit to JetBrains/compose-multiplatform-core that referenced this issue Nov 16, 2022
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
eymar pushed a commit to JetBrains/compose-multiplatform-core that referenced this issue Jan 13, 2023
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains/compose-multiplatform#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
MatkovIvan pushed a commit to MatkovIvan/compose-multiplatform that referenced this issue May 10, 2023
1. introduce ComposeWindow.exceptionHandler - can catch exceptions happened during recomposition, render, or event handling

2. if we use ComposeWindow directly, we don't change Swing behaviour - we just log the exception, and throw it further.

3. if we use Composable Window API, we show an error dialog and close the window. Users can override that via LocalWindowExceptionFactory.

Fixes JetBrains#663

Change-Id: I87c6e1d615951babbb070004cdcb5b87c07dc94f
Test: ./gradlew jvmTest desktopTest -Pandroidx.compose.multiplatformEnabled=true

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
@zoff99
Copy link

zoff99 commented Feb 28, 2024

can you show an example how to keep the app running after catching an exception like this? i can't get it to work. a compose exception always freezes the app. no way of recovery.

@hakanai
Copy link

hakanai commented Mar 16, 2024

Overriding LocalWindowExceptionHandlerFactory doesn't appear to work in the current stable release either. Debugger says my replacement exception handler is never called.

The existing ticket for it seemed to be #1764.

Setting ComposeWindow.exceptionHandler does work. That's clunky - I wanted something I could bury into a BetterErrorHandling composable which would work wherever you added it - but at least it gives us a working option.

It also leads me to wonder why setting the factory doesn't work... is it the case that it only works if you set it before displaying any windows? 🤔

My non-working example code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
desktop enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants