---
title: rtb-error
description: Canonical Error enum, Result alias, exit-code attachment and the miette diagnostic-hook pipeline for phpboyscout Rust tools.
---
# `rtb-error`
`rtb-error` is the error-handling foundation of the phpboyscout Rust toolkit.
It gives you four things:
- an umbrella [`Error`](reference/02-error-and-result.md) enum for application
scaffolding failures, and the `Result<T, E = Error>` alias;
- a [`hook`](reference/03-hook.md) module that installs a graphical diagnostic
renderer, a matching panic hook, and a support footer you can change at any
time;
- [exit-code attachment](reference/04-exit-code.md), so a specific error can
set a specific process exit code;
- a position on how errors should travel:
[as values, propagated with `?`, rendered once at the edge](explanation/01-errors-are-values.md).
Everything is built on [`miette`][miette] and [`thiserror`][thiserror]. If you
already use those directly, `rtb-error` adds types and a hook wrapper, not
capability — see
[what it does not do](explanation/03-what-this-does-not-do.md) before adopting
it.
Part of the [phpboyscout Rust toolkit](https://rust.phpboyscout.uk); extracted
from — and still consumed by —
[rust-tool-base](https://gitlab.com/phpboyscout/rust-tool-base).
## Install it
```console
$ cargo add rtb-error miette thiserror
```
`miette` and `thiserror` are separate because you need their derive macros in
your own crate. `rtb-error` re-exports the `Diagnostic` trait and derive, but
not `thiserror::Error`.
## What it looks like
```rust
use std::process::ExitCode;
use rtb_error::exit_code_of;
fn main() -> ExitCode {
rtb_error::hook::install_with_footer(|| {
"Report bugs at https://example.invalid/greet/issues".to_string()
});
rtb_error::hook::install_panic_hook();
match run() {
Ok(()) => ExitCode::SUCCESS,
Err(report) => {
eprintln!("Error: {report:?}");
ExitCode::from(exit_code_of(&report).unwrap_or(1))
}
}
}
```
```text
Error: greet::no_name
x no name given
help: pass a name: `greet Ada`
Report bugs at https://example.invalid/greet/issues
```
## Where to start
| Build one of these from an empty project | [Tutorial: give your CLI a diagnostic error path](tutorials/01-give-your-cli-a-diagnostic-error-path.md) |
| Do one specific thing — install the pipeline, set an exit code, add a footer | [How-to guides](how-to/index.md) |
| Look up a variant, a diagnostic code, a default or a failure mode | [Reference](reference/index.md) |
| Understand why there is no error-handler object | [Explanation](explanation/index.md) |
| Read the generated API docs | [docs.rs/rtb-error](https://docs.rs/rtb-error) |
## The one thing to get right
`miette`'s renderer lives in a process-global slot that can only be written
once, and it is filled by whichever comes first: your `install_*` call, or the
construction of the first `miette::Report` anywhere in the process. Install too
late and this crate's handler never runs, the footer never appears, and nothing
warns you.
Put the install calls at the very top of `main`, before any fallible work. The
mechanism is explained in
[Why the hook is installed once](explanation/02-why-the-hook-is-installed-once.md).
## What this does not do
It does not log, does not decide your exit code for you, does not redact
anything, and does not adapt rendering to the terminal the way `miette`'s own
default handler does. There are no Cargo features and no `no_std` build. The
full list, with the workaround for each, is
[What rtb-error does not do](explanation/03-what-this-does-not-do.md).
## Which crates use it
| [rtb-cli](https://docs.rs/rtb-cli) `0.9.0` | Installs all three hooks in `Application::run_with_args` when hooks are enabled, sourcing the footer from `ToolMetadata::help`; raises `Error::CommandNotFound` on an unknown subcommand; maps a report to a process exit code with `exit_code_of(report).unwrap_or(1)`; re-exports `Error` and `Result` from its prelude as `RtbError` and `RtbResult` |
| [rtb-app](https://docs.rs/rtb-app) `0.9.0` | Declares the dependency and defines the `HelpChannel` that `rtb-cli` turns into the footer text |
`rtb-config`, `rtb-credentials` and `rtb-telemetry` do **not** depend on
`rtb-error` in their currently published versions, despite what older
descriptions of the toolkit said.
None of these crates are required to use `rtb-error`. It has no dependency on
any of them and works in a plain `cargo new` binary — which is what the
[tutorial](tutorials/01-give-your-cli-a-diagnostic-error-path.md) builds.
[miette]: https://crates.io/crates/miette
[thiserror]: https://crates.io/crates/thiserror
## Further reading
The blog carries a curated route through this subject: **[Rust, and what survived the port](https://phpboyscout.uk/topics/rust/)** collects
everything written about it, ordered so you can start at the beginning rather
than newest-first.
!!! tip "Ask phpbotscout"
{ width="84" align=left style="border-radius:10px;margin-right:1rem" }
He answers questions about the projects over on the Discord, citing the docs
where they already cover it, and offering to raise an issue where they don't.
Bring a bug, an idea, or a questionable engineering decision.
[Join the Discord](https://discord.gg/mQzGbmGyzZ){ .md-button .md-button--primary }