flare adopts Mojo's typed errors
(https://docs.modular.com/mojo/manual/errors/#typed-errors) as the
default error-handling style for new code. Typed errors carry
structured fields, conform to Writable for print() /
String(e) rendering, and let callers pattern-match on
condition without String(e).startswith(...) heuristics.
This module ships the cross-module typed errors. Module-local
errors (e.g. :class:flare.http.template.TemplateError,
:class:flare.http.auth_extract.AuthError,
:class:flare.http.proxy_protocol.ProxyParseError) live next to
the parser that raises them, per the Mojo doc's "Define a custom
error type" guidance.
Convention summary
Prefer raises ConcreteError over bare raises.
Bare raises erases the error type at compile time (per
the Mojo doc § "Avoid bare raises with typed errors") so
callers can no longer access structured fields without
String(e) parsing.
One error type per function. When a function naturally
raises multiple unrelated conditions, use an
enumerated error type (one struct, comptime aliases
for each variant). When each condition needs different
carried data, use a Variant[...] of separate structs.
See :class:flare.http.template.TemplateError for the
enumerated pattern, :class:flare.http.proxy_protocol.ProxyParseError
for the structured-fields-on-one-struct pattern.
Wrap at trait / framework boundaries. The
:class:flare.http.handler.Handler trait and
:class:flare.http.extract.Extractor trait declare
bare raises for backwards compatibility with the original
surface. Impls that need typed errors internally should
raise typed errors directly from their bare-raises body — the
Mojo runtime preserves the typed error's identity (its
Writable rendering) even when the function signature is
bare-raises (see Mojo doc § "Avoid bare raises with typed
errors" / "type erasure only affects uncaught errors").
Don't mix error types in one try block. Mojo rejects
a try whose body calls functions raising different
typed-error types. Use sequential / nested try blocks
instead.
Two-tier naming. A type whose name ends Error names a
category of failure the caller may want to branch on as a group:
HttpError, IoError, NetworkError, ValidationError,
TlsHandshakeError, TemplateError. A type named as a bare
noun names one specific condition: ConnectionRefused,
AddressInUse, BrokenPipe, CertificateExpired,
DatagramTooLarge, TooManyRedirects. The split mirrors Rust's
io::Error versus io::ErrorKind, and it is why
ConnectionTimeout (a condition during the connect phase) and
Timeout (a condition during any I/O) can both exist in
:mod:flare.net.error without either being redundant.
Written down in v0.11. The existing names already follow it in the
main, but not everywhere, and the deviations are what a future
renaming pass should target -- not the convention.
What's in this module
- :class:
ValidationError — invalid input / argument validation
failures. Carries field + reason so callers can
distinguish per-field failures. HttpServer maps an uncaught
ValidationError to a sanitized 400 Bad Request (see
:func:map_handler_error).
- :class:
HttpStatusError — a handler-authored error that names the
exact status to return (mapped through the bare-raises
Handler.serve boundary by :func:map_handler_error).
- :class:
IoError — I/O-layer failure not covered by the more
specific :class:flare.net.NetworkError subtypes (e.g. a
generic syscall that returned -1 with a not-otherwise-
classified errno). Carries op + code (errno) +
detail.
Both types are Copyable (which implies Movable) and
Writable, and shaped per the Mojo typed-errors guidance.