Skip to content

Exceptions thrown by CoroutineExceptionHandler must be caught by handleCoroutineException() #562

Closed
@abusalimov

Description

@abusalimov

Currently exceptions thrown by CoroutineExceptionHandler are retrown from the handleCoroutineException(), possibly wrapped into a RuntimeException:

public actual fun handleCoroutineException(context: CoroutineContext, exception: Throwable) {
    try {
        /* invoke CoroutineExceptionHandler.handleException()
              and currentThread.uncaughtExceptionHandler.uncaughtException() */
    } catch (handlerException: Throwable) {
        // simply rethrow if handler threw the original exception
        if (handlerException === exception) throw exception
        // handler itself crashed for some other reason -- that is bad -- keep both
        throw RuntimeException("Exception while trying to handle coroutine exception", exception).apply {
            addSuppressed(handlerException)
        }
    }
}

It is unclear now what consequences this behavior can lead to, but the comment inside the catch { ... } clause, telling that -- that is bad -- is probably right.

It feels that handleCoroutineException() must guarantee not to throw, or at least make sure the exception is delivered to a proper piece of code that is expecting it.


Some background:

    val exceptionHandler = context[CoroutineExceptionHandler] ?: CoroutineExceptionHandler { coroutineContext, throwable ->
      LOG.error("Unhandled exception from $coroutineContext", throwable)
    }

This seemingly harmless piece of logic can actually throw an AssertionError in IDEA when running in unit testing mode. What is the right way of dealing with it?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions