Skip to content

Install the diagnostic pipeline

Add the calls to main

fn main() -> miette::Result<()> {
    rtb_error::hook::install_report_handler();
    rtb_error::hook::install_panic_hook();

    run()?;
    Ok(())
}

That is the whole wiring. install_report_handler makes every Report render graphically; install_panic_hook sends panics through the same renderer instead of the standard thread 'main' panicked at … line.

Put the calls before any fallible work

This matters more than it looks. miette's hook slot is filled by whichever happens first: your install call, or the construction of the first miette::Report anywhere in the process. If an error is built before you install, miette's own default handler is installed instead and yours never runs — with no error and no warning.

Concretely, this loses:

fn main() -> miette::Result<()> {
    let config = load_config()?;                      // may build a Report
    rtb_error::hook::install_report_handler();        // too late if it did
    
}

and this works:

fn main() -> miette::Result<()> {
    rtb_error::hook::install_report_handler();
    let config = load_config()?;
    
}

The install functions are cheap and idempotent, so there is no cost to putting them first.

Check that it took effect

There is no API for asking whether the handler is installed, so test it by looking at the output. Force an error and compare:

Error: greet::no_name

  x no name given
  help: pass a name: `greet Ada`

A diagnostic code on its own line and an indented help: line mean the graphical handler is rendering. A single bare line with no code and no help means it is not — either the install ran too late, or something is printing {report} instead of {report:?}.

Render a report yourself, without ?

Report's Debug implementation is the one that routes through the installed hook. Display is the bare message:

eprintln!("Error: {report:?}");   // code, help, footer
eprintln!("Error: {report}");     // "no name given"

GraphicalReportHandler::render_report called directly also bypasses the hook, which is useful in tests where you want deterministic output and no footer.

Use it with #[tokio::main]

The install calls go inside the function body, after the attribute has expanded:

#[tokio::main]
async fn main() -> miette::Result<()> {
    rtb_error::hook::install_report_handler();
    rtb_error::hook::install_panic_hook();
    run().await?;
    Ok(())
}

They are not async and do no I/O, so there is nothing to await.

What this does not give you

Installing the handler replaces miette's environment-aware MietteHandler with a GraphicalReportHandler. Wrap width becomes a fixed 200 columns, NO_GRAPHICS no longer switches to the narratable renderer, and terminal hyperlinks are always emitted. The full comparison is in the hook reference. If you need the narratable renderer, install your own miette hook instead and skip this crate's.