Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

no_std Support

masterror builds without the Rust standard library. The crate root declares #![cfg_attr(not(feature = "std"), no_std)], and the default std feature is the only thing standing between you and an embedded/WASM-friendly build:

[dependencies]
masterror = { version = "0.28", default-features = false }

alloc is required

masterror is no_std but not no_alloc. The crate unconditionally declares extern crate alloc and uses Cow<'static, str>, String, Arc and BTreeMap for messages, metadata and source chains. Your target needs a global allocator; pure core-only environments are not supported.

What works without std

The entire framework-agnostic core:

AreaAvailable in no_std
Core typesError / AppError, AppResult, AppErrorKind, AppCode
MetadataMetadata, Field, FieldValue, FieldRedaction, field::* helpers
ContextContext, ResultExt::{ctx, context}
Control flowensure!, fail!
Derives#[derive(Error)], #[derive(Masterror)] with all attributes
Wire typesProblemJson, ErrorResponse, CODE_MAPPINGS, mapping_for_code
Introspectionchain(), root_cause(), is/downcast/downcast_ref/downcast_mut, render_message()
Serdeserde with alloc (JSON serialization of wire types)

Error sources work through core::error::Error: the crate implements and consumes core::error::Error (aliased internally as CoreError) instead of std::error::Error, so with_source(...), source chains and downcasting are fully functional in no_std builds.

use masterror::{AppCode, AppError, AppErrorKind, field};

let err = AppError::new(AppErrorKind::Timeout, "deadline exceeded")
    .with_field(field::u64("attempt", 3));

assert_eq!(err.code, AppCode::Timeout);
assert_eq!(err.metadata().len(), 1);

What requires std

Every runtime integration explicitly re-enables std in its feature definition. From Cargo.toml:

  • tracing, metrics, backtrace, colored
  • axum, actix, multipart, tonic, openapi
  • serde_json, redis, validator, config, tokio, reqwest, teloxide, init-data, frontend, turnkey

backtrace needs std::backtrace::Backtrace and environment access; colored needs TTY detection; the web and client integrations need their host crates, which are themselves std-only.

CI feature matrix

The no_std CI job (.github/workflows/ci.yml) checks these combinations on every pull request and push to main:

JobCommandVerifies
barecargo check --no-default-featurestrue no_std + alloc build
std-onlycargo check --features stddefault std surface
tracingcargo check --no-default-features --features tracingsingle telemetry feature builds standalone
metricscargo check --no-default-features --features metricssame for metrics
coloredcargo check --no-default-features --features coloredsame for colored
all-featurescargo check --all-featuresfull feature union

Note the semantics: only the bare job is a genuine no_std compilation. tracing = [..., "std"], metrics = [..., "std"] and colored = [..., "std"] transitively re-enable std, so those jobs verify that each telemetry feature is self-sufficient when defaults are off — not that telemetry works without the standard library. If you need telemetry, you need std.

Practical setup

Library crates that want to stay transport-agnostic and no_std-compatible:

[dependencies]
masterror = { version = "0.28", default-features = false }

[features]
std = ["masterror/std"]

The binary or service crate then turns on std plus whatever integrations it needs:

[dependencies]
masterror = { version = "0.28", features = ["axum", "tracing", "metrics"] }

Because AppErrorKind, AppCode and the wire types live in the no_std core, domain crates can classify errors and even build ProblemJson payloads while the HTTP mapping happens only in the service crate — see Best Practices.

Toolchain

The crate targets edition 2024 with rust-version = "1.96" in Cargo.toml. core::error::Error (the foundation of no_std source chains) has been stable since Rust 1.81, so no nightly features are involved.

See also: Feature Flags · Getting Started · Best Practices