redacted-error
Stable public error messages with debug-only diagnostic detail.
redacted-error is a small facade for Rust errors that cross crate, process,
API, or protocol boundaries. It lets applications expose stable public error
codes and messages while preserving rich diagnostics in debug builds.
Features
message!for displayable static public-facing messages.message_string!for owned public-facing messages.detail!,detail, anddisplayfor debug-only runtime diagnostics.ErrorCodeandPublicErrortraits for stable public API responses.impl_redacted_debug!to keep releaseDebugfrom leaking enum fields.- Optional static string obfuscation behind the default
obfuscatefeature.
The public API does not expose the obfuscation implementation. Today the
default backend is obfstr; later releases can replace that backend without
requiring callers to rename macros.
message! returns a Message wrapper, not a borrowed &'static str. That is
intentional: it keeps backend-specific lifetime behavior out of caller code.
Use message_string! when a trait or response type needs an owned String.
Usage
[]
= "0.1"
Disable static string obfuscation:
[]
= { = "0.1", = false }
Example
use message as m;
use Error;
impl_redacted_debug!;
In debug builds, Display can include diagnostic detail:
listener bind failed: 127.0.0.1:8080: address already in use
In release builds, Display and Debug stay public-safe:
listener bind failed
For API responses, use stable structured fields rather than parsing Display:
Security
This crate is a leakage-reduction tool, not a confidentiality boundary.
- The
obfuscatefeature only raises the bar against trivialstrings-style inspection of compiled binaries. It is not a defense against a debugger, dynamic instrumentation, symbol tables, or any motivated reverse engineer. Do not treat obfuscated literals as secret. - Diagnostic-detail stripping is gated on
cfg(debug_assertions). Cargo's standardreleaseprofile turns this off, but[profile.release] debug-assertions = truere-enables it — and with it, everydetail!/display/detailcall leaks runtime detail in release builds. Avoid that combination if redaction matters. - The
detail!macro skips evaluating its format arguments in release. Thedetailanddisplayfree functions still evaluate (and drop) their argument; prefer the macro when the argument has nontrivial cost or side effects.
Migration Notes
For existing code using obfstr in error messages:
use obfstr as s;
Prefer:
use message as s;
Then replace dynamic error details with redacted_error::detail! or
redacted_error::display.
For code currently using the local error-detail crate, the intended mapping
is:
| Local API | Public crate API |
|---|---|
error_detail::obfstr!("...") |
redacted_error::message!("...") |
error_detail::obfstring!("...") |
redacted_error::message_string!("...") |
error_detail::detail!("...") |
redacted_error::detail!("...") |
error_detail::display(err) |
redacted_error::display(err) |
error_detail::ErrorCode |
redacted_error::ErrorCode |
error_detail::impl_redacted_debug! |
redacted_error::impl_redacted_debug! |
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.