# How to Use Abseil C++ Exceptions: Portable Exception Handling for Library Authors

> Learn to use Abseil C++ exceptions for portable exception handling. Compile and execute safely with or without -fno-exceptions using Abseil's helpers and StatusOr.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: how-to-guide
- Published: 2026-07-15

---

**Abseil C++ exceptions are managed through centralized throwing helpers in [`absl/base/throw_delegate.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/throw_delegate.h), portable exception-aware macros in [`absl/base/macros.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/macros.h), and the `absl::StatusOr<T>` value-or-error wrapper, enabling your code to compile and execute safely with or without `-fno-exceptions`.**

Abseil is designed to function correctly in environments where C++ exceptions are disabled. The `abseil/abseil-cpp` repository provides abstraction mechanisms that detect exception support at compile time and adapt behavior accordingly. Understanding these facilities ensures your library code remains portable across different build configurations.

## Detecting Exception Support with `ABSL_HAVE_EXCEPTIONS`

Abseil automatically detects whether exception handling is available via the `ABSL_HAVE_EXCEPTIONS` preprocessor macro. This definition is controlled by your build system (Bazel or CMake) based on compiler flags and is declared in [`absl/base/config.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/config.h).

When `ABSL_HAVE_EXCEPTIONS` is undefined—typically when compiling with `-fno-exceptions`—Abseil substitutes safe alternatives that avoid throwing. You can inspect this macro to conditionally compile exception-specific logic, though the Abseil macros handle this automatically.

## Throwing Standard Exceptions with [`throw_delegate.h`](https://github.com/abseil/abseil-cpp/blob/main/throw_delegate.h)

Never call `throw` directly in code that might be compiled without exception support. Instead, use the **exception-throwing helpers** declared in [`absl/base/throw_delegate.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/throw_delegate.h). These functions are marked `[[noreturn]]` and delegate to standard library exception types.

Available helpers include:
- `absl::ThrowStdInvalidArgument(const std::string&)`
- `absl::ThrowStdOutOfRange(const std::string&)`
- `absl::ThrowStdRuntimeError(const std::string&)`
- `absl::ThrowStdLogicError(const std::string&)`

When exceptions are enabled, these functions throw the corresponding `std::` exception. When disabled, they call `std::terminate()` via the implementation in `throw_delegate.cc`.

```cpp
#include "absl/base/throw_delegate.h"

void ValidateIndex(int idx, int size) {
  if (idx < 0 || idx >= size) {
    // Throws std::out_of_range, or terminates if exceptions are disabled.
    absl::ThrowStdOutOfRange("index out of range");
  }
}

```

## Writing Portable Exception Handlers with Abseil Macros

To write `try/catch` blocks that compile regardless of exception settings, use the exception-aware macros defined in [`absl/base/macros.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/macros.h):

- `ABSL_INTERNAL_TRY` expands to `try` when exceptions are enabled, otherwise `if (true)`
- `ABSL_INTERNAL_CATCH_ANY` expands to `catch (...)` when enabled, otherwise `else if (false)`
- `ABSL_INTERNAL_RETHROW` expands to `throw;` when enabled, otherwise a no-op

```cpp
#include "absl/base/macros.h"
#include "absl/base/throw_delegate.h"
#include <iostream>

void ProcessWithFallback(bool trigger_error) {
  ABSL_INTERNAL_TRY {
    if (trigger_error) {
      absl::ThrowStdRuntimeError("processing failed");
    }
    std::cout << "Success\n";
  } ABSL_INTERNAL_CATCH_ANY {
    std::cout << "Error caught\n";
    ABSL_INTERNAL_RETHROW;  // Only rethrows if exceptions are enabled.
  }
}

```

When `ABSL_HAVE_EXCEPTIONS` is undefined, the `ABSL_INTERNAL_TRY` block becomes a simple `if (true)` statement with zero runtime overhead for exception handling.

## Handling Errors with `absl::StatusOr<T>` and `BadStatusOrAccess`

For functions that may fail, prefer returning `absl::StatusOr<T>` from [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h) instead of throwing. This wrapper holds either a value of type `T` or an `absl::Status` error.

The `.value()` accessor behaves differently based on exception settings:
- **With exceptions**: Throws `absl::BadStatusOrAccess` if the status is not OK.
- **Without exceptions**: Calls `std::terminate()`.

```cpp
#include "absl/status/statusor.h"
#include <string>
#include <iostream>

absl::StatusOr<int> ParseInt(std::string_view s) {
  try {
    return std::stoi(std::string(s));
  } catch (const std::invalid_argument&) {
    return absl::InvalidArgumentError("not an integer");
  }
}

void UseValue() {
  auto result = ParseInt("42");
  // Check status explicitly to avoid throwing/terminating.
  if (!result.ok()) {
    std::cerr << "Failed: " << result.status() << '\n';
    return;
  }
  // Safe to access value here.
  int v = result.value();
  std::cout << "Value: " << v << '\n';
}

```

Always call `result.ok()` before accessing `.value()` if you want to avoid the exception or termination path.

## Best Practices for Exception-Safe Abseil Code

Follow these guidelines when working with Abseil C++ exceptions:

- **Use [`throw_delegate.h`](https://github.com/abseil/abseil-cpp/blob/main/throw_delegate.h) helpers** instead of raw `throw` statements in headers or library code that may be compiled with `-fno-exceptions`.
- **Wrap `try/catch` with `ABSL_INTERNAL_*` macros** to maintain compatibility across different build configurations.
- **Prefer `absl::StatusOr<T>`** over exceptions for recoverable errors and expected failure modes.
- **Reserve exceptions** for unrecoverable logic errors or contract violations where program termination is acceptable.
- **Check `result.ok()`** before calling `.value()` on `StatusOr` objects unless you intend to propagate the error via exception.

## Summary

- **Abseil detects exception support** automatically via the `ABSL_HAVE_EXCEPTIONS` macro defined in [`absl/base/config.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/config.h).
- **Use throwing helpers** like `absl::ThrowStdInvalidArgument` from [`absl/base/throw_delegate.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/throw_delegate.h) to safely throw standard exceptions even when compiling with `-fno-exceptions`.
- **Write portable exception handlers** using `ABSL_INTERNAL_TRY`, `ABSL_INTERNAL_CATCH_ANY`, and `ABSL_INTERNAL_RETHROW` from [`absl/base/macros.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/macros.h).
- **Handle errors with `absl::StatusOr<T>`** to return values or statuses explicitly, noting that `.value()` throws `absl::BadStatusOrAccess` only when exceptions are enabled.
- **Never call `throw` directly** in header-only or library code that must support exception-disabled builds.

## Frequently Asked Questions

### What happens if I call `absl::ThrowStdOutOfRange` when exceptions are disabled?

When exceptions are disabled, `absl::ThrowStdOutOfRange` and other helpers in [`absl/base/throw_delegate.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/throw_delegate.h) call `std::terminate()` instead of throwing `std::out_of_range`. This ensures the program exits safely rather than entering undefined behavior, maintaining a consistent failure mode across build configurations.

### How does `ABSL_INTERNAL_CATCH_ANY` work without exceptions?

The `ABSL_INTERNAL_CATCH_ANY` macro expands to `else if (false)` when `ABSL_HAVE_EXCEPTIONS` is undefined. This makes the catch block dead code that the compiler optimizes away, eliminating any runtime overhead while preserving source compatibility with exception-enabled builds.

### Should I use `absl::StatusOr<T>` or exceptions for error handling in Abseil?

Prefer `absl::StatusOr<T>` for recoverable errors and expected failure modes, as it works identically with or without exceptions enabled. Reserve exceptions thrown via [`absl/base/throw_delegate.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/throw_delegate.h) for unrecoverable logic errors or contract violations where program termination is an acceptable alternative.

### Where is the `ABSL_HAVE_EXCEPTIONS` macro defined?

The `ABSL_HAVE_EXCEPTIONS` macro is defined in [`absl/base/config.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/config.h) based on compiler feature detection. It is set automatically by Abseil's build configuration (Bazel or CMake) when the compiler supports exceptions, allowing the library to adapt its behavior without manual intervention.