rtb-error 0.6.5

Error types and the diagnostic report pipeline. Part of the phpboyscout Rust toolkit.
Documentation
---
title: Crate surface
description: Everything rtb-error exports, its MSRV, its Cargo features, its dependencies and its semver policy.
tags: [reference, api]
---

# Crate surface

## What `rtb-error` exports

The crate root re-exports two `miette` items and the whole of `exit_code`:

```rust
pub use miette::{Diagnostic, Report};

pub mod exit_code;
pub use exit_code::{exit_code_of, ExitCoded, WithExitCode};

pub type Result<T, E = Error> = std::result::Result<T, E>;
pub enum Error { /* … */ }

pub mod hook;
```

`pub use miette::Diagnostic` re-exports the name in both namespaces, so
`#[derive(rtb_error::Diagnostic)]` works as well as `impl rtb_error::Diagnostic
for …`. The `thiserror::Error` derive is **not** re-exported, so add `thiserror`
to your own `Cargo.toml` if you want it.

## Which Cargo features does rtb-error have?

**None.** The crate declares no `[features]` table. There is nothing to turn
on and nothing to turn off, which also means:

- `miette`'s `fancy` feature is always compiled in. `rtb-error` depends on
  `miette` with `features = ["fancy"]`, so the graphical
  renderer, terminal detection and their transitive dependencies
  (`owo-colors`, `supports-color`, `terminal_size`, `textwrap` and friends)
  are in every build.
- There is no `no_std` build. `hook` uses `std::sync::OnceLock`,
  `std::sync::RwLock`, `std::panic` and thread-locals.

If you need a smaller graph, depend on `miette` and `thiserror` directly and
skip `rtb-error`; it adds types and one hook wrapper, not capability.

## Dependencies

| Crate | Features | Why |
|---|---|---|
| [`miette`]https://crates.io/crates/miette | `fancy` | `Diagnostic` trait, `Report`, the graphical renderer, the panic hook |
| [`thiserror`]https://crates.io/crates/thiserror | default | The `#[error(…)]` derive used by `Error` |

The version requirements are in
[`Cargo.toml`](https://gitlab.com/phpboyscout/rust/error/-/blob/main/Cargo.toml),
which Renovate keeps current; this page does not repeat them.

Dev-dependencies (`cucumber`, `tokio`, `trybuild`) do not reach consumers.

## Minimum supported Rust version

`rust-version = "1.82"`, edition 2021. Consumers on edition 2024 are fine,
because edition is per-crate.

The repository additionally pins an exact toolchain in `rust-toolchain.toml`
for its own CI, and Renovate moves the pin. That pin exists because the `trybuild`
compile-fail fixtures match rustc's diagnostic output byte for byte and a
floating channel re-renders them; it is **not** a requirement on consumers.

## Safety guarantee

`src/lib.rs` carries `#![forbid(unsafe_code)]`. `forbid` cannot be re-permitted
by an inner `#[allow]`, so the guarantee holds for the whole crate, not just
the modules that remembered to keep it. The `Cargo.toml` lint table sets
`unsafe_code = "deny"` at the package level so test files can opt out where
they genuinely need to; the shipped library is the stronger `forbid`.

## Semver policy

`Error` is `#[non_exhaustive]`. Adding a variant is therefore a minor release,
not a breaking one, and any `match` on it outside this crate must carry a
wildcard arm. A `match` without one is a compile error, and a `trybuild`
fixture (`tests/trybuild/non_exhaustive.rs`) exists only to keep that true.

`ExitCoded` is **not** `#[non_exhaustive]`, but it has private fields and no
public constructor other than `ExitCoded::new`, so the same protection applies
by construction.

Releases are cut by [colophon](https://gitlab.com/phpboyscout/colophon) from
Conventional Commits; nobody tags by hand. Tags are `rtb-error-v<version>` rather than
`v<version>`, kept that way for consistency with the `rtb-error-v*` tags
inherited from the rust-tool-base monorepo. The crate is pre-`1.0`, so Cargo's
caret requirement `"0.6"` will not cross a minor bump for you; treat a minor
bump as potentially breaking and read the
[changelog](https://gitlab.com/phpboyscout/rust/error/-/blob/main/CHANGELOG.md).

## Where the tests live

| Suite | File | Covers |
|---|---|---|
| Unit / acceptance | `tests/unit.rs` | The `Error` enum's codes, help and `Display`; hook idempotency; footer behaviour including a panicking footer closure |
| Exit codes | `src/exit_code.rs` (`mod tests`) | Attach, read back, transparent delegation, survival through `?` |
| BDD | `tests/features/error.feature`, `tests/steps/` | Six Gherkin scenarios over the same public API |
| Compile-fail | `tests/trybuild/` | An exhaustive `match` on `Error` must not compile |

`cargo nextest run` runs all four. The hook tests need nextest's
process-per-test isolation, because `miette`'s hook is process-global and
set-once. Under a shared-process runner the first test to install wins and
the rest observe its handler. `just test` falls back to `cargo test` if
nextest is absent, and those tests may then behave differently.