Kotlinx.coroutines: Default uncaught exception handler is ignored

Created on 7 Aug 2017  路  3Comments  路  Source: Kotlin/kotlinx.coroutines

Hi, I'm new to kotlin coroutines and couldn't figure out from the docs if the following is expected and if there is some other way to set a default uncaught exception handler: my problem is that in this example

import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.swing.Swing
import java.awt.BorderLayout
import java.lang.Exception
import javax.swing.JButton
import javax.swing.JFrame
import javax.swing.WindowConstants

fun main(args: Array<String>) {
  Thread.setDefaultUncaughtExceptionHandler { thread: Thread, throwable: Throwable ->
    println("Uncaught throwable in thread ${thread.name}")
    throwable.printStackTrace()
  }

  val btn = JButton("Hello")
  btn.addActionListener {
    async(Swing) {
      throw Exception("World!")
    }
  }

  val frame = JFrame()
  frame.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
  frame.add(btn, BorderLayout.CENTER)
  frame.pack()
  frame.isVisible = true
}

The default thread uncaught exception handler is not being called.

Most helpful comment

Looks like you have to implement CoroutineExceptionHandler

private class UncaughtCoRoutineExceptionHandler :
  CoroutineExceptionHandler, AbstractCoroutineContextElement(CoroutineExceptionHandler.Key) {
  override fun handleException(context: CoroutineContext, exception: Throwable) {
    println("handled")
  }
}

private fun singleThread(name: String): CoroutineContext {
  return newSingleThreadContext(name).plus(UncaughtCoRoutineExceptionHandler())
}

fun main(args: Array<String>) = runBlocking<Unit>(CommonPool) {
  launch(singleThread("handler")) {
    throw RuntimeException()
  }
  delay(1, TimeUnit.SECONDS)
}

All 3 comments

Looks like you have to implement CoroutineExceptionHandler

private class UncaughtCoRoutineExceptionHandler :
  CoroutineExceptionHandler, AbstractCoroutineContextElement(CoroutineExceptionHandler.Key) {
  override fun handleException(context: CoroutineContext, exception: Throwable) {
    println("handled")
  }
}

private fun singleThread(name: String): CoroutineContext {
  return newSingleThreadContext(name).plus(UncaughtCoRoutineExceptionHandler())
}

fun main(args: Array<String>) = runBlocking<Unit>(CommonPool) {
  launch(singleThread("handler")) {
    throw RuntimeException()
  }
  delay(1, TimeUnit.SECONDS)
}

The async function returns a future called Deferred: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/async.html

Just like with any other future-style or async functions in other languages, this future contains the result of the execution or the corresponding exception that happened during exception.

You code ignores the result of the async function in your code, thus the exception just sits there. If you want exception to be propagated to uncaught exception handler, then you should use launch instead of async:
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/launch.html

I see, thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Pitel picture Pitel  路  3Comments

zach-klippenstein picture zach-klippenstein  路  3Comments

mhernand40 picture mhernand40  路  3Comments

mgj picture mgj  路  3Comments

iTanChi picture iTanChi  路  3Comments