AssetError reference¶
AssetError is the only error type the crate produces. It is
#[non_exhaustive], derives thiserror::Error and
miette::Diagnostic, and every variant carries a stable diagnostic
code under the rtb::assets:: namespace.
#[non_exhaustive]
pub enum AssetError {
NotFound(String),
NotUtf8 { path: String },
Parse { path: String, format: &'static str, message: String },
}
Because the enum is #[non_exhaustive], a match on it needs a _
arm; a new variant in a future release will not break your build.
Only three methods return a Result: open_text, load_merged_yaml
and load_merged_json. open, exists and list_dir cannot fail —
they return None, false and an empty Vec respectively.
NotFound¶
Diagnostic code rtb::assets::not_found. The payload is the requested
path, unchanged.
Raised when no registered layer provides the path. Causes, in rough order of likelihood:
- The path does not match how the asset is keyed. Embedded and
in-memory layers compare keys literally, so a leading
./, a leading/, or a backslash separator will not match. - The layer you expected to hold it was never registered, or was
registered with its arguments swapped — print the
Assetswith{:?}and check the labels. - A
DirectorySourceroot does not exist. That is not an error in itself; the layer simply contributes nothing. - The path names a directory. Directories are listable, not readable.
NotUtf8¶
Diagnostic code rtb::assets::not_utf8. Raised only by open_text,
when a layer provided bytes that are not valid UTF-8.
The bytes are discarded rather than lossily converted. Read binary
assets with open, which returns Option<Vec<u8>> and never inspects
the contents.
A UTF-8 byte-order mark does not trigger this — the BOM is valid UTF-8
and arrives as a leading \u{feff} in the returned String. Strip it
yourself if the consumer of the string will not tolerate it.
Parse¶
Diagnostic code rtb::assets::parse, with the help text "verify the
file is well-formed YAML" (or JSON). Three fields:
| Field | Contents |
|---|---|
path |
either <path> (layer |
format |
"YAML" or "JSON" |
message |
the underlying parser's message, verbatim |
Raised in three distinct situations, which the path field
distinguishes:
- A contributing layer's file is malformed.
pathnames the layer. The load aborts; there is no fallback to lower layers. - A contributing layer's YAML bytes are not UTF-8. Also names the
layer, also reported as a parse failure rather than
NotUtf8. - The merged document does not fit
T.pathis bare, because merging has already happened and no single layer can be blamed. A missing required field, a number out of range for its type, or a type mismatch all land here.
The path field is a human-readable description, not a path you can
feed back into open. If you need the clean path for a retry or a log
field, keep hold of the string you passed in.
Rendering an AssetError¶
Display gives the one-line message above. miette's report handler
gives the code and help text as well, which is what a CLI built on the
toolkit will print:
match assets.load_merged_yaml::<Config>("config.yaml") {
Ok(config) => config,
Err(e) => return Err(miette::Report::new(e)),
}
The diagnostic codes are part of the public contract and are safe to match on or document in a tool's own troubleshooting guide.
What is deliberately not an error¶
- A missing layer root. A
DirectorySourcepointed at a directory the user has not created behaves as an empty layer. - A rejected path.
../../etc/passwdreturnsNonefromopenandNotFoundfromopen_text— the same as any absent file, with no indication that a security rule fired. See Why path traversal is rejected lexically for the reasoning. - An unreadable file. Permission denied is indistinguishable from absent, and a lower layer gets its turn.
- An empty overlay.
Assets::default()is valid and every read simply finds nothing.