diff --git a/docs/topics/debugging.md b/docs/topics/debugging.md index c0df045ed5..d18df7f465 100644 --- a/docs/topics/debugging.md +++ b/docs/topics/debugging.md @@ -46,6 +46,10 @@ It is easy to demonstrate with actual stacktraces of the same program that await The only downside of this approach is losing referential transparency of the exception. +> Note that suppressed exceptions are not copied and are left intact in the cause +> in order to prevent cycles in the exceptions chain, obscure`[CIRCULAR REFERENCE]` messages +> and even [crashes](https://jira.qos.ch/browse/LOGBACK-1027) in some frameworks + ### Stacktrace recovery machinery This section explains the inner mechanism of stacktrace recovery and can be skipped. diff --git a/kotlinx-coroutines-core/common/src/Debug.common.kt b/kotlinx-coroutines-core/common/src/Debug.common.kt index 12b23295f4..1381ecd882 100644 --- a/kotlinx-coroutines-core/common/src/Debug.common.kt +++ b/kotlinx-coroutines-core/common/src/Debug.common.kt @@ -35,6 +35,7 @@ public interface CopyableThrowable where T : Throwable, T : CopyableThrowable * For better debuggability, it is recommended to use original exception as [cause][Throwable.cause] of the resulting one. * Stacktrace of copied exception will be overwritten by stacktrace recovery machinery by [Throwable.setStackTrace] call. * An exception can opt-out of copying by returning `null` from this function. + * Suppressed exceptions of the original exception should not be copied in order to avoid circular exceptions. */ public fun createCopy(): T? }