error-engine
A shared Rust crate to centralize error, warning, and info presentation
across personal projects. It does not replace thiserror or tracing — it
sits on top of them as a message catalog + presentation layer.
Each project defines its errors as an enum with thiserror (re-exported
by this crate) and implements the EngineDiagnostic trait. A TOML catalog
file maps each diagnostic's stable code to a message template and an
optional hint, so wording can be edited without touching Rust code.
Install
Not published to crates.io — add it as a path or git dependency:
[]
= { = "https://github.com/<you>/error-engine" }
Enable the cli feature if you want colored terminal output (Engine::print):
[]
= { = "https://github.com/<you>/error-engine", = ["cli"] }
Usage
-
Define your errors with
thiserror, usingerror_engine::thiserror::Errorso you don't needthiserroras a separate dependency:use Error; -
Implement
EngineDiagnostic— a stablecode(), aseverity(), and optionalcontext()key-value pairs to interpolate into the template:use ; -
Write a catalog TOML file at your project's root, e.g.
errors.toml:[] = "Could not find the configuration file at {path}" = "Check that the path is correct, or create one with `myapp init`" [] = "Could not connect to the database: {reason}"- Each table key (
[CODE]) must match exactly thecode()returned by the correspondingEngineDiagnostic. templateis required,hintis optional.{key}placeholders are substituted with values fromcontext(). A placeholder with no matching value is left literal in the text — it never panics.UNK-000is reserved by the crate (see Failure behavior) and should not be reused as a project-defined code.
- Each table key (
-
Load the catalog and build an
Engine:use ;
Run the bundled examples for a working end-to-end reference:
Output modes
| Method | Returns | Use case |
|---|---|---|
message() |
String |
GUI apps: plain text only, no logging, no color |
log() |
nothing, goes to tracing |
Structured logging (files, services) |
print() |
nothing, goes to stdout/stderr | CLIs: colored output with hint (cli feature) |
print() lives behind the cli feature flag so GUI/service projects don't
pull in terminal-only dependencies (owo-colors).
Failure behavior (harmless by design)
Nothing about diagnostic rendering should ever panic or crash the
application — a broken catalog or a typo'd code is a documentation problem,
not a runtime crash. Two failure modes are unified under a single reserved
code, UNK-000:
- The catalog itself failed to load (file missing, unreadable, or invalid TOML).
- The catalog loaded fine, but the requested code has no entry in it.
In both cases, rendering returns a message built around UNK-000 stating
which of the two happened, instead of failing.
Catalog::load(path)— strict loader, returnsResult<Catalog, EngineError>. Use at startup if you want the app to refuse to run without a valid catalog.Catalog::load_or_fallback(path)— infallible loader, and the recommended entry point. A broken or missing catalog never panics; every diagnostic that would have failed instead renders asUNK-000with an explanatory message.
Project structure
error-engine/
├── Cargo.toml
├── .cargo/
│ └── config.toml # rustflags = ["-D", "warnings"]
├── src/
│ ├── lib.rs # public re-exports (includes `pub use thiserror`)
│ ├── diagnostic.rs # trait EngineDiagnostic + enum Severity
│ ├── catalog.rs # TOML catalog loading/rendering + UNK-000 fallback
│ ├── engine.rs # struct Engine: message() / log() / print()
│ └── error.rs # crate's own internal errors (catalog loading)
├── examples/
│ ├── basic.rs # minimal usage: message() + log()
│ ├── cli.rs # usage with the `cli` feature: print()
│ └── errors.toml # sample catalog used by both examples
└── tests/
└── catalog.rs # catalog loading/rendering tests
Testing
Non-goals (v0.1)
- No compile-time validation that codes used in the project exist in the catalog.
- No
#[derive(EngineDiagnostic)]macro. - No shared/inherited catalogs across projects (one catalog = one project).
- No i18n (multiple languages per catalog).
See docs/error-engine-design.md for the full design rationale.