# How to Implement Custom Exception Translators in Catch2

> Learn how to implement custom exception translators in Catch2 using the CATCH_TRANSLATE_EXCEPTION macro. Convert C++ exceptions to readable strings for better test output.

- Repository: [Catch Org/Catch2](https://github.com/catchorg/Catch2)
- Tags: how-to-guide
- Published: 2026-07-30

---

**Catch2 provides the `CATCH_TRANSLATE_EXCEPTION` macro to register functions that convert user-defined C++ exceptions into human-readable strings for test output.**

Catch2 is a modern, header-only C++ testing framework that enables developers to implement custom exception translators for domain-specific error types. When tests throw user-defined exceptions, these translators ensure the framework displays descriptive messages rather than cryptic failure reports. The mechanism relies on static registration via macros and a centralized registry that processes exceptions at runtime.

## How Exception Translation Works in Catch2

The exception translation system in Catch2 operates through three coordinated components defined in the `src/catch2/` directory.

### The Core Components

**`CATCH_TRANSLATE_EXCEPTION` macro** – Defined in [[`catch_translate_exception.hpp`](https://github.com/catchorg/Catch2/blob/main/catch_translate_exception.hpp)](https://github.com/catchorg/Catch2/blob/devel/src/catch2/catch_translate_exception.hpp), this macro generates a static function with your custom signature and automatically registers it with the framework during program startup.

**`ExceptionTranslatorRegistrar`** – Located in the same header (lines 55‑61), this template class wraps your translation function inside an `IExceptionTranslator` implementation and passes it to the global registry.

**`ExceptionTranslatorRegistry`** – Implemented in [[`catch_exception_translator_registry.hpp`](https://github.com/catchorg/Catch2/blob/main/catch_exception_translator_registry.hpp)](https://github.com/catchorg/Catch2/blob/devel/src/catch2/internal/catch_exception_translator_registry.hpp), this class maintains a list of all registered translators. When a test throws an exception, the registry's `translateActiveException()` method iterates through translators until one successfully converts the exception to a `std::string`.

The registration occurs during static initialization, ensuring translators are available before any test cases execute. If you compile with `CATCH_CONFIG_DISABLE`, the macro expands to a plain function definition without registration overhead.

## Implementing a Custom Exception Translator

To implement custom exception translators in your test suite, define your exception class, register a translation function, and write tests that trigger the exceptions.

### Define Your Exception Class

Create a custom exception that inherits from `std::runtime_error` or implements the standard exception interface.

```cpp
// my_exceptions.hpp
#pragma once
#include <stdexcept>
#include <string>

class MyError : public std::runtime_error {
public:
    explicit MyError( std::string const& msg ) 
        : std::runtime_error(msg) {}
};

```

### Register the Translator

Include [`catch_translate_exception.hpp`](https://github.com/catchorg/Catch2/blob/main/catch_translate_exception.hpp) and use the `CATCH_TRANSLATE_EXCEPTION` macro to register a function that converts your exception to a string.

```cpp
// translator.cpp
#include <catch2/catch_translate_exception.hpp>
#include "my_exceptions.hpp"

CATCH_TRANSLATE_EXCEPTION( MyError const& e ) {
    return std::string("MyError: ") + e.what();
}

```

The macro automatically generates the boilerplate to register this function with the `ExceptionTranslatorRegistry` at static initialization time.

### Write Tests That Use the Translator

When tests throw `MyError`, Catch2 catches the exception, invokes your translator, and displays the resulting string in the failure output.

```cpp
// test_my_error.cpp
#include <catch2/catch_test_macros.hpp>
#include "my_exceptions.hpp"

TEST_CASE( "custom exception translation", "[exception]" ) {
    REQUIRE_THROWS_AS( 
        throw MyError("something went wrong"), 
        MyError 
    );
}

```

Running this test produces output like:

```text
================================================================================
MyError: something went wrong
================================================================================

```

## Working with Non-Standard Exception Types

The translation mechanism works for any C++ type, not just standard exceptions. You can implement custom exception translators for structs or primitive wrappers without inheritance.

```cpp
struct Foo { int id; };

CATCH_TRANSLATE_EXCEPTION( Foo const& f ) {
    return "Foo with id = " + std::to_string(f.id);
}

```

When a test throws `Foo`, the registry invokes this translator and displays the formatted ID in the test report.

## Key Implementation Files

Understanding the source structure helps when debugging translation issues:

- **[`src/catch2/catch_translate_exception.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_translate_exception.hpp)** – Contains the `CATCH_TRANSLATE_EXCEPTION` macro definition and `ExceptionTranslatorRegistrar` template.
- **[`src/catch2/internal/catch_exception_translator_registry.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/internal/catch_exception_translator_registry.hpp)** – Implements the `ExceptionTranslatorRegistry` class that stores translators and executes `translateActiveException()`.
- **[`src/catch2/interfaces/catch_interfaces_exception.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/interfaces/catch_interfaces_exception.hpp)** – Declares the abstract `IExceptionTranslator` interface and registry accessors.
- **[`extras/catch_amalgamated.hpp`](https://github.com/catchorg/Catch2/blob/main/extras/catch_amalgamated.hpp)** – Single-header version containing the same translation logic for embedded deployments.

## Summary

- **Use the `CATCH_TRANSLATE_EXCEPTION` macro** to register translation functions that convert custom exceptions to `std::string` representations.
- **Registration happens automatically** at static initialization time via `ExceptionTranslatorRegistrar` before tests run.
- **The `ExceptionTranslatorRegistry`** iterates through registered translators when `translateActiveException()` is called, stopping at the first successful match.
- **Non-standard types are supported** – any C++ type can be translated, not just `std::exception` derivatives.
- **Conditional compilation** respects `CATCH_CONFIG_DISABLE`, expanding the macro to a plain function when exceptions are disabled.

## Frequently Asked Questions

### What happens if no translator matches my exception type?

If the `ExceptionTranslatorRegistry` exhausts all registered translators without a match, Catch2 falls back to default exception handling. For types inheriting from `std::exception`, it displays the `what()` message; for other types, it shows a generic "unknown exception" message according to the implementation in [`catch_exception_translator_registry.hpp`](https://github.com/catchorg/Catch2/blob/main/catch_exception_translator_registry.hpp).

### Can I register multiple exception translators in the same test executable?

Yes. Each `CATCH_TRANSLATE_EXCEPTION` invocation generates a distinct registrar object, and the `ExceptionTranslatorRegistry` maintains a vector of all translators. The system attempts translation in registration order, returning the first successful result. You should register translators for specific derived types before base types to ensure precise matching.

### Does exception translation work when exceptions are disabled?

When you define `CATCH_CONFIG_DISABLE`, the `CATCH_TRANSLATE_EXCEPTION` macro expands to only the function definition without the registration code. The translator function remains available for manual invocation, but Catch2 will not automatically catch and translate exceptions during test execution since exception handling is disabled.

### Where should I place translator registration code?

Place `CATCH_TRANSLATE_EXCEPTION` definitions in `.cpp` files rather than headers to avoid multiple definition errors. Since registration occurs during static initialization, you can place translators in any compilation unit linked into your test binary. Ensure you include [`catch_translate_exception.hpp`](https://github.com/catchorg/Catch2/blob/main/catch_translate_exception.hpp) and link against the Catch2 library or include the amalgamated header.