Skip to content

Crate surface

What rtb-error exports

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

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 — 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 = { version = "7.6.0", 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 Version Why
miette 7.6.0, feature fancy Diagnostic trait, Report, the graphical renderer, the panic hook
thiserror 2.0.19 The #[error(…)] derive used by Error

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 — edition is per-crate.

The repository additionally pins an exact toolchain in rust-toolchain.toml (currently 1.97.1) for its own CI. 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 — there is a trybuild fixture (tests/trybuild/non_exhaustive.rs) whose whole job is 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 release-plz 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.

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.