#[oopsie]Expand description
Attribute macro — the primary way to define an oopsie error type.
Generates context selectors, Display, Error, and Debug impls in one
attribute. No need for #[derive(Debug, Oopsie)].
§Usage
use oopsie::ResultExt as _;
#[oopsie::oopsie]
pub enum MyError {
#[oopsie("Connection to {host} failed")]
Connect { host: String, source: std::io::Error },
}
let result: Result<(), std::io::Error> = Err(std::io::Error::other("refused"));
let err = result.context(my_oopsies::Connect { host: "db.example.com" }).unwrap_err();
assert_eq!(err.to_string(), "Connection to db.example.com failed");§Diagnostics
Pass traced to automatically inject a backtrace field (and a span-trace when
the tracing feature is enabled):
#[oopsie::oopsie(traced)]
pub enum MyError {
#[oopsie("Connection failed")]
Connect,
}§Parameters
The bare #[oopsie] adds no diagnostics; it is equivalent to
#[derive(Debug, Oopsie)]. The arguments below tune what gets generated;
each has its own subsection further down.
| Parameter | Effect |
|---|---|
traced | Inject a backtrace field (and a span-trace under the tracing feature), plus an auto error code |
path | Path to the oopsie crate in generated impls |
debug | Skip the automatic Debug derive |
Injects trace-capture fields into every variant (or the struct): a backtrace, a
span trace, and the caller location, all enabled by default. The nested options
tune each part — mentioning one never disables the others — and traced(false)
opts the type out entirely. With traced active, an auto-generated error code is
also attached to each variant unless the nested code option disables it.
On enums, a variant can override tracing with #[oopsie(traced)] or
#[oopsie(traced = false)]. This toggle is boolean-only at variant scope: it
enables or disables the variant’s traced injection as a whole. It only applies
when the enum itself is traced; a variant traced on an enum that isn’t traced
is a compile error.
Forms: traced, traced = true, traced = false, traced(true), traced(false),
traced(enabled = ...),
traced(backtrace(...), spantrace(...), timestamp(...), location = ..., packed = ..., boxed = ..., code(...)).
Variant forms (enum variants only): traced, traced = true, traced = false.
§Example
#[oopsie::oopsie(traced)]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}Overrides the path to the oopsie crate used in the generated code, given as a
string. Needed when oopsie is re-exported under a different path or renamed in
Cargo.toml. Defaults to ::oopsie; a container-level #[oopsie(path = ...)]
on the type itself wins over this.
Forms: path = "some::path", path = some::path.
§Example
// A real custom path must name a crate that actually re-exports `oopsie`,
// which can't exist inside this crate's own doctest.
#[oopsie::oopsie(path = "my_crate::reexports::oopsie")]
pub enum AppError {
#[oopsie("boom")]
Boom,
}By default #[oopsie::oopsie] adds a Debug derive to the error type (a Debug
impl is required by std::error::Error). Set debug = false to skip that
injection when you supply a hand-written impl Debug instead. An existing
Debug derive on the type is always respected and never duplicated.
Forms: debug, debug = true, debug = false, debug(true), debug(false).
§Example
use std::fmt;
#[oopsie::oopsie(debug = false)]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
impl fmt::Debug for AppError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("custom debug")
}
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(format!("{err:?}"), "custom debug");
}§traced(...) options
These keys are spelled nested inside traced(...). backtrace/spantrace
take an optional settings block (r#type, boxed, enabled); timestamp
takes chrono/provide; packed/boxed are pair-level layout flags.
| Option | Effect |
|---|---|
backtrace | Enable/tune the captured backtrace (default on) |
spantrace | Enable/tune the captured span trace (default on; captures nothing without the tracing feature) |
timestamp | Inject an auto-captured timestamp field (default off) |
location | Inject an auto-captured call-site Location field (default on) |
packed | Store both traces as one (Backtrace, SpanTrace) field |
boxed | Box the injected trace field(s) |
code | Tune (or disable) the auto error code |
chrono | Use chrono::DateTime<Local> timestamps |
provide | Expose the timestamp via the provider API |
r#type | Override the injected type for this part |
enabled | Explicit on/off inside a settings block |
Inside traced(...): enables and tunes capture of the backtrace (default: on).
Mentioning this part never disables the others. backtrace(false) drops the
backtrace, and a settings block tunes its type, boxing, and on/off state.
Forms: backtrace, backtrace = true, backtrace = false,
backtrace(true), backtrace(false),
backtrace(r#type = Path, boxed = ..., enabled = ...).
§Example
#[oopsie::oopsie(traced(backtrace, spantrace(false)))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}Inside traced(...): enables and tunes capture of the span trace (default: on).
Mentioning this part never disables the others. spantrace(false) drops the
span trace, and a settings block tunes its type, boxing, and on/off state.
Without the tracing feature the span trace captures nothing.
Forms: spantrace, spantrace = true, spantrace = false,
spantrace(true), spantrace(false),
spantrace(r#type = Path, boxed = ..., enabled = ...).
§Example
#[oopsie::oopsie(traced(spantrace, backtrace(false)))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}Inside traced(...): injects an auto-captured timestamp field (default: off). A
bare timestamp records a SystemTime; a settings block opts into the chrono
type or the provider exposure.
Forms: timestamp, timestamp = true, timestamp = false,
timestamp(true), timestamp(false),
timestamp(chrono = ..., provide = ..., enabled = ...).
§Example
#[oopsie::oopsie(traced(timestamp))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}Inside traced(...): injects an auto-captured &'static Location<'static>
field recording the call site where the error was built (default: on). The
location is surfaced via Diagnostic::oopsie_location and rendered by Report
even when backtraces are disabled. Use location = false to opt out.
Forms: location, location = true, location = false,
location(true), location(false).
§Example
#[oopsie::oopsie(traced(location = false))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}Inside traced(...): stores the backtrace and span trace as one packed
(Backtrace, SpanTrace) field (default: on). packed = false keeps them as two
separate fields, which also allows boxing each independently. Packing requires
backtrace and spantrace to share one boxing mode.
Forms: packed, packed = true, packed = false, packed(true),
packed(false).
§Example
#[oopsie::oopsie(traced(packed = false))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}Inside traced(...): boxes the injected trace field(s) (default: on), keeping
the error type small. At the pair level it applies to both traces; placed inside
backtrace(...) or spantrace(...) it tunes that one trace. boxed = false
stores the trace(s) inline.
Forms: boxed, boxed = true, boxed = false, boxed(true),
boxed(false).
§Example
#[oopsie::oopsie(traced(boxed = false))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}With traced, attaches an auto-generated error code to every variant (or the
struct) that has no explicit #[oopsie(code = "...")], surfaced via
Diagnostic::oopsie_error_code. The generated code is the item’s path,
module_path::Type::Variant; transparent items are excluded.
traced(code = false) turns the auto code off, and traced(code(r#type = Path))
overrides the error-code type (default ErrorCode).
Forms: traced(code), traced(code = true), traced(code = false),
traced(code(true)), traced(code(false)),
traced(code(r#type = Path, enabled = ...)).
§Example
use oopsie::Diagnostic as _;
#[oopsie::oopsie(traced(code(r#type = ::oopsie::ErrorCode)))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert!(err.oopsie_error_code().is_some());
}Inside timestamp(...): uses chrono::DateTime<Local> instead of SystemTime
as the injected timestamp type (default: off). Opt-in, and needs oopsie’s
chrono feature enabled.
Forms: chrono, chrono = true, chrono = false, chrono(true),
chrono(false).
§Example
// `chrono = true` only compiles with oopsie's `chrono` feature, which this
// crate's own doctests don't enable.
#[oopsie::oopsie(traced(timestamp(chrono = true)))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}Inside timestamp(...): also exposes the captured timestamp through the
std::error::Request provider API (active with the unstable feature), so
callers can retrieve it with Error::request_value (default: off). Opt-in.
Forms: provide, provide = true, provide = false, provide(true),
provide(false).
§Example
#[oopsie::oopsie(traced(timestamp(provide = true)))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}Overrides the injected type for this part: the trace field type inside
backtrace(...) or spantrace(...), or the error-code type inside code(...).
Spelled with the raw identifier r#type since type is a keyword.
Forms: r#type = "some::Path", r#type = some::Path.
§Example
#[oopsie::oopsie(traced(backtrace(r#type = ::oopsie::Backtrace)))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}An explicit on/off switch accepted in any settings block, e.g.
backtrace(enabled = false, r#type = ...). It lets a block both carry other
settings and state whether the part is active; a settings block without it counts
as enabled.
Forms: enabled, enabled = true, enabled = false.
§Example
#[oopsie::oopsie(traced(backtrace(enabled = false)))]
pub enum AppError {
#[oopsie("boom")]
Boom,
}
fn main() {
let err = app_oopsies::Boom.build();
assert_eq!(err.to_string(), "boom");
}With traced, every variant (or the struct itself) also gets an automatic
error code unless it is transparent or carries an explicit
#[oopsie(code = "...")]. The code is module_path::Type for structs and
module_path::Type::Variant for enum variants; Report renders it as
Error[...]: in the report header.
Container-level #[oopsie(...)] attributes (module, vis, size, etc.)
are placed on the type itself, not in the attribute macro’s argument list.