errs

A library for handling errors with reasons for Rust
Overview
errs is an error handling library for Rust designed to focus on the "Reason" behind an error.
Expressing "Why It Failed" via the Type System
Rather than treating errors as simple message strings or type-erased objects, it embraces a design that expresses "why it failed" through types, allowing for safe and clear propagation and determination.
For error reasons, you can use anything from lightweight types like String to type-safe definitions using enum or struct, all handled flexibly with the same API.
By using an enum in particular, you can not only express failure factors within the type system but also hold contextual information in its fields, propagating the situation and relevant data at the time of the error as-is.
Furthermore, since reasons can be determined in a type-safe manner using reason::<T>() or match_reason, you can avoid fragile error handling that relies on string comparisons.
Decentralized Error Definition and Traceability
errs encourages defining error reasons close to where they occur.
This eliminates the need to share a massive, monolithic error type across the entire application, enabling a highly maintainable design while keeping dependencies between modules clean.
Type information is utilized to identify the reason, and the type identifiers required for this determination are resolved statically at compile time.
This provides type-safe error handling with minimal runtime overhead.
The core Err type of the library implements std::error::Error, allowing it to integrate naturally with standard Rust error handling, including the ? operator.
It can also retain lower-layer errors as causes (source errors), enabling you to manage the "Reason" of the upper layer and the "Cause" of the lower layer separately.
Additionally, it automatically records the file name and line number when an error is generated, making log output and failure analysis effortless.
Powerful Error-Instantiation Notification & Monitoring Ecosystem
Furthermore, errs features a mechanism to notify error generation events.
By enabling the notify or notify-tokio feature, an automatic notification can be sent to registered handlers the exact moment an Err is created.
It supports synchronous handlers, generic asynchronous handlers, and asynchronous handlers tailored for Tokio.
It accommodates both dynamic registration within functions and static global registration via macros.
This makes it easy to implement logging, monitoring, metrics collection, and integration with telemetry systems.
While anyhow-like libraries place importance on "propagating errors flexibly," and thiserror-like libraries focus on "making error type definitions easy", errs emphasizes "expressing failure reasons through types and observing their occurrence".
This library is ideal when you want to clearly manage the semantics of errors occurring within an application while integrating seamlessly with monitoring and operations infrastructure.
Install
In Cargo.toml, write this crate as a dependency:
[]
= "1.0.0"
If you want to use error notification, specify the notify or notify-tokio in the dependency features.
The notify feature is for general use, while the notify-tokio feature is for use with the Tokio runtime.
[]
= { = "1.0.0", = ["notify"] }
If you are using Tokio, you should specify notify-tokio:
[]
= { = "1.0.0", = ["notify-tokio"] }
Usage
Locally Defined Reasons and Instantiate an Err with Them
An Err struct can be instantiated with any arbitrary error reason.
Typically, a variant of an enum defined to indicate the cause or context of the error is used as the reason.
This variant does not need to belong to a single, centrally managed enum; rather, it is preferable to define it close to where the error using it as a reason actually occurs.
use Err;
let err = Errnew;
An Err can also be instantiated using Err::with_source, which accepts the underlying cause error along with the reason.
use ;
use Err;
let io_error = new;
let err = Errwith_source;
Type-Safe Reason Identification
By using the reason::<R>(&self) method, you can extract the error reason as the specified type R.
Since the return value is Result<&R, &Err>, you can use a match statement to safely branch and identify the reason in a type-safe manner.
match err.
Methods like match_reason allow you to write error reason identification and fallback processing elegantly using method chaining, without having to nest multiple match statements.
let val: u8 = err...or_result?;
Function-based Error Handler Registration
To enable this feature, you must specify the feature
notifyornotify-tokioinCargo.toml.
This crate optionally provides a feature to notify pre-registered error handlers when an Err
is instantiated.
Multiple error handlers can be registered, and you can choose to receive notifications either
synchronously or asynchronously.
To register handlers inside a function (like main), you can use the following functions:
add_sync_err_handler: For synchronous handlers.add_async_err_handler: For general-purpose asynchronous handlers.add_tokio_async_err_handler: For Tokio-based asynchronous handlers.
Error notifications will not occur until the fix_err_handlers function is called.
This function locks the current set of error handlers, preventing further additions and
enabling notification processing.
// In your main function or initialization code:
add_sync_err_handler;
add_async_err_handler;
add_tokio_async_err_handler;
// Fix the handlers to start receiving notifications.
fix_err_handlers;
Macro-based Error Handler Registration
To enable this feature, you must specify the feature
notifyornotify-tokioinCargo.toml.
Alternatively, you can register handlers from a static context (outside a function body) using macros. These are useful for setting up global handlers that are compiled into your program.
add_sync_err_handler!: Statically registers a synchronous handler.add_async_err_handler!: Statically registers a general-purpose asynchronous handler.add_tokio_async_err_handler!: Statically registers a Tokio-based asynchronous handler.
These macros require function pointers, not closures.
use ;
use ;
use Err;
use ;
use Arc;
// Define a static synchronous handler
add_sync_err_handler!;
// Define a static asynchronous handler
add_async_err_handler!;
// Define a static Tokio-based asynchronous handler
add_tokio_async_err_handler!;
// Later, in your main function, you still need to fix the handlers.
// errs::fix_err_handlers();
Supported Rust versions
This crate supports Rust 1.80.1 or later.
)
License
Copyright (C) 2025-2026 Takayuki Sato
This program is free software under MIT License. See the file LICENSE in this distribution for more details.