# How absl::StatusOr<T> Handles Error Propagation in Abseil C++

> Discover how absl::StatusOr<T> efficiently handles error propagation in Abseil C++. Learn about its status storage, copy/move operations, and explicit error checking for robust code.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: internals
- Published: 2026-07-12

---

**Error propagation in `absl::StatusOr<T>` works by storing a non-OK `absl::Status` inside a discriminated union, forwarding that status during copy/move operations, and enforcing explicit handling through runtime checks that crash or throw `BadStatusOrAccess` if the value is accessed while in an error state.**

The `absl::StatusOr<T>` class in the Abseil C++ library provides a monadic container for error propagation, acting as a discriminated union that holds either a value of type `T` or an `absl::Status` indicating failure. This pattern eliminates the need for output parameters or exceptions while ensuring that error states flow explicitly through your codebase. Understanding how `absl::StatusOr` propagates errors requires examining its internal storage mechanics, construction constraints, and strict value-access semantics.

## Construction from Error Status

`absl::StatusOr<T>` propagates errors starting at construction. The class provides a template constructor that accepts any type convertible to `absl::Status`, enabling direct initialization from error values.

### The Status-Accepting Constructor

In [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h) (lines 63–71), the constructor uses SFINAE traits to validate status conversions:

```cpp
template <typename U = absl::Status,
          std::enable_if_t<internal_statusor::IsConstructionFromStatusValid<
                                false, T, U>::value, int> = 0>
StatusOr(U&& v) : Base(std::forward<U>(v)) {}

```

This constructor delegates to internal machinery that calls `EnsureNotOk()`, rejecting accidental construction with an OK status. The implementation guarantees that a `StatusOr` object can only hold a status if that status represents an actual error condition, preventing the ambiguous state of "success without a value."

## Querying the Object State

Once constructed, `absl::StatusOr` provides explicit methods to inspect whether it holds a value or an error, enabling disciplined error propagation throughout the call stack.

### Checking Success with ok() and status()

The `ok()` method in [`statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/statusor.h) (lines 57–73) provides a fast boolean check:

```cpp
ABSL_MUST_USE_RESULT bool ok() const { return this->status_.ok(); }

```

The `status()` method returns the stored `absl::Status` object, yielding `OkStatus()` when a value is present or the error code when in a failed state. These accessors allow callers to branch on error conditions before attempting value extraction:

```cpp
absl::StatusOr<int> result = ComputeValue();
if (!result.ok()) {
  return result.status();  // Propagate error upward
}

```

## Value Access and Safety Guarantees

`absl::StatusOr` enforces strict semantics that prevent silent error dropping. Any attempt to access the stored value while in an error state triggers immediate program termination or an exception.

### Runtime Enforcement with EnsureOk()

The value accessors—including `value()`, `operator*()`, and `operator->()`—internally call `self().EnsureOk()`, implemented in the `OperatorBase` class within [`absl/status/internal/statusor_internal.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/internal/statusor_internal.h). If the object is not OK, this mechanism throws `absl::BadStatusOrAccess` or crashes the process, depending on configuration.

This design ensures that **error propagation cannot be accidentally ignored**. You must explicitly check `ok()` before dereferencing, or the program will halt:

```cpp
absl::StatusOr<std::string> data = LoadFile("config.txt");
// Dangerous: Will crash if LoadFile failed
std::string contents = *data;  // Calls EnsureOk() internally

```

## Error Propagation Through Assignment

When copying or moving `StatusOr` objects, the implementation propagates errors by inspecting the source object's state and forwarding the appropriate payload.

### Copy Assignment Semantics

In `absl/status/statusor.cc` (lines 35–41), the copy assignment logic explicitly branches on the source state:

```cpp
if (other.ok()) {
  this->Assign(*other);          // Copy the value
} else {
  this->AssignStatus(other.status()); // Propagate the error
}

```

This ensures that if the source contains an error, the destination receives that same error status rather than a default-constructed value.

### Move Assignment Semantics

The move assignment path (lines 44–50) follows identical logic but transfers ownership:

```cpp
if (other.ok()) {
  this->Assign(*std::move(other));
} else {
  this->AssignStatus(std::move(other).status());
}

```

Move semantics preserve error propagation while avoiding unnecessary copies of the `absl::Status` object, maintaining efficiency when returning `StatusOr` from functions.

## Safe Access Patterns

Beyond strict enforcement, `absl::StatusOr` provides utilities for handling errors gracefully without throwing exceptions.

### Providing Fallbacks with value_or()

The `value_or()` method, defined in [`statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/statusor.h) (lines 73–80), returns the held value if OK, otherwise constructs the supplied default:

```cpp
absl::StatusOr<int> maybe = ParseInt(user_input);
int value = maybe.value_or(0);  // Returns 0 if parsing failed

```

This pattern allows local error recovery without polluting the calling function with explicit error checking.

### Suppressing Unused Error Warnings

The `IgnoreError()` method acts as a no-op to silence static analysis tools that warn about ignored return values:

```cpp
GetOptionalConfig().IgnoreError();  // Explicitly acknowledge we don't care about errors here

```

## Internal Storage Architecture

The error propagation mechanism relies on `StatusOrData` in [`absl/status/internal/statusor_internal.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/internal/statusor_internal.h), which manages the discriminated union storage. This internal class handles the complex lifecycle of holding either a `T` or an `absl::Status`, ensuring proper destruction and move semantics while preventing the simultaneous existence of both states.

## Summary

- **Explicit error storage**: `absl::StatusOr<T>` holds either a value of type `T` or a non-OK `absl::Status`, rejecting construction with OK status via `EnsureNotOk()`.
- **Strict access semantics**: Value accessors invoke `EnsureOk()`, crashing or throwing `BadStatusOrAccess` if accessed in an error state.
- **Automatic propagation**: Copy and move operations in `statusor.cc` check `ok()` and forward errors via `AssignStatus()`, ensuring errors flow through assignment chains.
- **Safe utilities**: `value_or()` provides fallback values without exceptions, while `IgnoreError()` satisfies static analysis requirements.

## Frequently Asked Questions

### What happens if I try to access the value of a StatusOr containing an error?

Accessing the value through `value()`, `operator*()`, or `operator->()` calls `EnsureOk()` internally. If the object is not OK, the program will either crash or throw `absl::BadStatusOrAccess`, depending on your build configuration. This guarantees that error states cannot be silently ignored.

### Can I construct a StatusOr with an OK status and no value?

No. The constructor that accepts `absl::Status` uses `EnsureNotOk()` to reject OK statuses at runtime. A `StatusOr` must contain either a valid value of type `T` or a non-OK status indicating failure. This invariant prevents the ambiguous state of "success with no data."

### How does StatusOr handle errors when copying between different types?

When copying or assigning a `StatusOr<U>` to a `StatusOr<T>`, the implementation checks the source's `ok()` state. If the source contains an error, it propagates that error status regardless of the type difference. If the source is OK, it attempts to convert the value from `U` to `T`, which may fail if the types are incompatible.

### Is there a performance cost to using StatusOr for error propagation?

The overhead is minimal. `absl::StatusOr` uses a discriminated union with move semantics to avoid heap allocation. The `ok()` check compiles to a simple integer comparison, and the `ABSL_MUST_USE_RESULT` attribute ensures errors are handled at compile time where possible. The primary cost is the branch prediction when checking status, which is comparable to traditional error code checking.