load and load_and_merge_subcommand_for return OrthoResult<T>, an alias
for Result<T, Arc<OrthoError>>. OrthoError wraps errors from clap, file
I/O and figment. Failures during the final merge of CLI values over
configuration sources surface as the Merge variant, providing clearer
diagnostics when the combined data is invalid. When multiple sources fail, the
errors are collected into the Aggregate variant so callers can inspect each
individual failure. Consumers should handle these errors appropriately, for
example by printing them to stderr and exiting. If required fields are missing
after merging, the crate returns OrthoError::MissingRequiredValues with a
user‑friendly list of missing paths and hints on how to provide them. For
example:
Missing required values:
sample_value (use --sample-value, SAMPLE_VALUE, or file entry)
Preserving `clap` display exits
When a user passes --help or --version, clap surfaces specialised
ErrorKind::DisplayHelp / DisplayVersion errors so applications can print
usage text and exit successfully. Deriving OrthoConfig often goes hand in
hand with Cli::try_parse() so applications can map errors into their own
types. Before performing that conversion, call
ortho_config::is_display_request to detect these cases and delegate to
err.exit():
use clap::Parser;
use ortho_config::{is_display_request, OrthoConfig};
fn parse_cli() -> Result<MyCli, CliError> {
match MyCli::try_parse() {
Ok(cli) => Ok(cli),
Err(mut err) => {
if is_display_request(&err) {
err.exit();
}
Err(CliError::ArgumentParsing(err.into()))
}
}
}
The examples/hello_world crate applies this pattern in main.rs. Behavioural
tests assert that both --help and --version exit with code 0 so regressions
are caught automatically.
Aggregating multiple errors
To return multiple errors in one go, use OrthoError::aggregate. It accepts
any iterator of items that can be converted into Arc<OrthoError> so both
owned and shared errors are supported. If the list might be empty,
OrthoError::try_aggregate returns Option<OrthoError> instead of panicking:
use std::sync::Arc;
use ortho_config::OrthoError;
// From bare errors
let err = OrthoError::aggregate(vec![
OrthoError::Validation { key: "port".into(), message: "must be positive".into() },
OrthoError::gathering(figment::Error::from("invalid")),
]);
// From shared errors
let err = OrthoError::aggregate(vec![
Arc::new(OrthoError::Validation { key: "x".into(), message: "bad".into() }),
OrthoError::gathering_arc(figment::Error::from("boom")),
]);
Gathering vs Merge errors
OrthoConfig distinguishes between two phases of configuration loading:
-
Gathering (
OrthoError::Gathering): Errors that occur while reading configuration sources (files, environment variables). These indicate problems with the source data itself, such as malformed TOML or invalid JSON. -
Merge (
OrthoError::Merge): Errors that occur while combining layers and deserializing the final configuration. These indicate incompatibilities between the merged data and the target struct, such as type mismatches or invalid field values.
When deserializing the final merged configuration fails (for example, because a
field has an invalid type after all layers are combined), the error is reported
as Merge. This distinction helps diagnose whether an issue lies with a
specific source file (Gathering) or with the combined result of all layers
(Merge).
Mapping errors ergonomically
To reduce boiler‑plate when converting between error types, the crate exposes small extension traits:
OrthoResultExt::into_ortho()convertsResult<T, E>intoOrthoResult<T>whenE: Into<OrthoError>(e.g.,serde_json::Error).OrthoMergeExt::into_ortho_merge()convertsResult<T, figment::Error>intoOrthoResult<T>asOrthoError::Merge.OrthoJsonMergeExt::into_ortho_merge_json()convertsResult<T, serde_json::Error>intoOrthoResult<T>asOrthoError::Merge, preserving location information from the JSON parser.IntoFigmentError::into_figment()convertsArc<OrthoError>(or&Arc<OrthoError>) intofigment::Errorfor interop in tests or adapters, cloning the inner error to preserve structured details where possible.ResultIntoFigment::to_figment()convertsOrthoResult<T>intoResult<T, figment::Error>.
Examples:
use ortho_config::{OrthoMergeExt, OrthoResultExt, ResultIntoFigment};
fn sanitize<T: serde::Serialize>(v: &T) -> ortho_config::OrthoResult<serde_json::Value> {
serde_json::to_value(v).into_ortho()
}
fn extract(fig: figment::Figment) -> ortho_config::OrthoResult<MyCfg> {
fig.extract::<MyCfg>().into_ortho_merge()
}
fn interop(r: ortho_config::OrthoResult<MyCfg>) -> Result<MyCfg, figment::Error> {
r.to_figment()
}