---
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
| [`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
| 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.