NVIDIA / NVIDIA/cccl

Error Handling in CUB (and beyond)

Open
#6,259 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
2.5k
Forks
486
Avg merge
2d 6h
Merged PRs (30d)
295

Description

We agree that `_CCCL_ASSERT` (in debug mode) is the right mechanism to validate preconditions, postconditions, and invariants in device-side code.
The main reasons are performance and the lack of non-intrusive mechanisms on device code (such as exceptions).

By contrast, host-side code-which primarily provides lightweight dispatch functionality-has no robust, well-established way to handle errors, internally or externally.

Historically, CUB's public interfaces use return codes (`cudaError_t`). This approach is problematic for the following reasons:

- It provides no insight into the cause of the error or how to resolve it.
- It is easy to ignore, despite the `[[nodiscard]]` attribute.

Ideally, we want to strictly validate user input, prevent undefined behavior, and help users identify and fix problems.
In the following sections, we present the pros and cons of common error-handling approaches in the context of CUB's design.

### Assertions (`_CCCL_ASSERT`)

Pros:
- Clearly describes the problem.
- Reports the exact code location that generated the problem.
- Works well with debuggers/sanitizers; can produce a stack trace with additional information.

Cons:
- Available only in debug mode; requires a full, expensive rebuild.

Additional notes:
- This approach is non-recoverable as it terminates the program; assertions are intended solely for logic errors.
- `_CCCL_VERIFY` can also be used to force an always-enabled assertion.

### Exceptions (`throw`)

Pros:
- Clearly describes the problem.
- Cannot be ignored.
- Works well with a debugger.
- Requires no code changes to propagate errors; supports easy composition.

Cons:
- Represents a sudden change in API behavior; CUB is not expected to throw exceptions.
- Would introduce both return codes and exceptions for handling invalid inputs.
- Better suited to exceptional situations outside user control (e.g., failing to open a file).
- Debugging exceptions is less intuitive than debugging assertions.
- Potential side effects include code bloat, higher compile times, and slower runtime in failure paths.
- Must handle cases where users do not want exceptions.
- Handling exceptions can be verbose.

### Print and Terminate

Pros:
- Clearly describes the problem.
- Cannot be ignored.
- Requires no API changes.
- Less invasive than exceptions.
- Printing behavior can be controlled via environment variables.

Cons:
- Hard to debug.
- Termination may be unacceptable in some contexts (e.g., UI applications).

This strategy is used in:
- Kokkos (can be opted out in favor of exceptions).
- RAJA.
- CUDA Math libraries (C interfaces)

### `cuda::std::expected`

Pros:
- Allows users to choose between error codes and exceptions.

Cons:
- Breaks the API.
- Errors are easy to ignore.
- Verbose.

### Error Code Object

This approach adds a parameter to accept an error code object (or an error callback).
See [HPX manual - Error handling](https://hpx-docs.stellar-group.org/branches/master/html/manual/miscellaneous.html). A similar strategy is used in [`std::filesystem`](https://en.cppreference.com/w/cpp/filesystem/absolute.html).

Pros:
- Users have complete control over error handling.

Cons:
- Requires a new overload for each public API.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.