Error Handling
Standout owns the shell adapter: handlers and hooks return errors as data, and
App::run performs the final stderr write and process exit. Ordinary handler,
hook, render, pipe, and final-write failures use status 1; Clap usage failures
use status 2.
Ordinary application errors
Return ordinary errors through HandlerResult with ?. Standout adds the
normal handler diagnostic framing and reports status 1:
#![allow(unused)] fn main() { fn handler(_matches: &ArgMatches, _ctx: &CommandContext) -> HandlerResult<View> { let view = load_view()?; Ok(Output::Render(view)) } }
Do not print or call process::exit from handlers. This keeps capture APIs,
TestHarness, output ownership, and real process behavior on the same seam.
Preserving an authoritative external failure
Use ExternalFailure only when another operation owns the status and diagnostic
contract, such as a delegated Git invocation. Construction rejects status 0.
The diagnostic is a verbatim stderr payload: Standout adds no Error: prefix
and no trailing newline.
#![allow(unused)] fn main() { use standout::cli::{ExternalFailure, HandlerResult}; fn handler(_matches: &ArgMatches, _ctx: &CommandContext) -> HandlerResult<View> { let output = run_git()?; if !output.status.success() { let status = output.status.code().and_then(|code| u8::try_from(code).ok()).unwrap_or(1); let diagnostic = String::from_utf8_lossy(&output.stderr).into_owned(); return Err(ExternalFailure::new(status, diagnostic)?.into()); } Ok(Output::Render(to_view(output))) } }
A supported pre-dispatch check uses the same ExternalFailure interface:
#![allow(unused)] fn main() { Hooks::new().pre_dispatch(|_matches, _ctx| { let failure = ExternalFailure::new(128, "fatal: repository not found\n") .expect("128 is nonzero"); Err(HookError::pre_dispatch_external(failure)) }) }
The escape hatch is not an error-mapping registry. Wrapping an ordinary error
does not change its status, and external declarations are not recognized from
post-dispatch or post-output hooks. Attach an underlying cause with
ExternalFailure::with_source when one exists.
Capture callers match RunResult::Error, then inspect
RunErrorKind::External, error.exit_status(), and error.as_str(). See
Execution Outcomes and Testing.