---
title: "TestFailureHandler"
description: "Handles Compose UI test failures for custom diagnostics or artifact processing."
type: "interface"
---
## API Reference

> Source set: Common

```kotlin
public interface TestFailureHandler
```

Handles Compose UI test failures for custom diagnostics or artifact processing.

Implementations are registered in a [TestFailurePolicy](/jetpack-compose/androidx.compose.ui/ui-test/classes/TestFailurePolicy/api) within a [ComposeUiTestConfig](/jetpack-compose/androidx.compose.ui/ui-test/classes/ComposeUiTestConfig/api) and
execute in the order provided. If a handler throws an exception, the framework catches and
attaches it as a suppressed exception to `FailureContext.error`, ensuring the original test
failure is never masked.

Handlers execute synchronously on the test thread in a post-mortem state where the Compose
hierarchy, coroutine scopes, and UI registries have already been torn down. As a result,
interactive testing APIs like `ComposeUiTest.waitForIdle` or [onNodeWithTag](/jetpack-compose/androidx.compose.ui/ui-test/functions/onNodeWithTag/api) cannot be called
within a handler.

Because handlers execute after the test timeout has elapsed, blocking calls such as file IO or
network operations can delay or stall the test runner indefinitely. Handlers that perform heavy
IO should enforce their own tight timeouts or dispatch work to background threads.

## Functions

### onTestFailed

> Source set: Common

```kotlin
public fun onTestFailed(context: FailureContext)
```

Invoked synchronously on the test thread when a Compose UI test fails.

#### Parameters

| | |
| --- | --- |
| context | The [FailureContext](/jetpack-compose/androidx.compose.ui/ui-test/classes/FailureContext) containing the root `Throwable` and any generated [FailureArtifact](/jetpack-compose/androidx.compose.ui/ui-test/classes/FailureArtifact)s. |

## Code Examples

### testFailureHandlerSample

```kotlin
@Sampled
fun testFailureHandlerSample() {
    val customFailureHandler = TestFailureHandler { context ->
        val storage = PlatformTestStorageRegistry.getInstance()

        context.artifacts.forEach { artifact ->
            when (artifact.type) {
                FailureArtifact.Type.Screenshot -> {
                    // Example: Read the screenshot bytes to upload to a custom dashboard
                    // val inputStream = storage.openInputFile(artifact.fileName)
                }
                FailureArtifact.Type.UiHierarchy -> {
                    // Example: Get the URI to share or process further
                    // val uri = storage.getOutputFileUri(artifact.fileName)
                }
            }
        }
    }

    val testConfig =
        ComposeUiTestConfig(
            failurePolicy =
                TestFailurePolicy(
                    screenshotCaptureMode = CaptureMode.Enabled,
                    uiHierarchyCaptureMode = CaptureMode.Enabled,
                    failureHandlers = listOf(customFailureHandler),
                )
        )

    runComposeUiTest(config = testConfig) {
        setContent { /* Your Compose UI here */ }

        // If this assertion fails, the framework will:
        // 1. Take a screenshot
        // 2. Dump the UI hierarchy
        // 3. Call customFailureHandler.onTestFailed
        onNodeWithTag("non_existent_button").assertExists()
    }
}
```
