#[non_exhaustive]pub enum Error {
InvalidRequest(Cow<'static, str>),
Config(Cow<'static, str>),
Provider {
kind: ProviderErrorKind,
message: String,
retry_after: Option<Duration>,
source: Option<Box<dyn Error + Send + Sync + 'static>>,
},
Cancelled,
DeadlineExceeded,
Interrupted {
kind: InterruptionKind,
payload: Value,
},
ModelRetry {
hint: RenderedForLlm<String>,
attempt: u32,
},
Serde(Error),
Auth(AuthError),
UsageLimitExceeded(UsageLimitBreach),
}Expand description
Aggregate error returned from public entelix-core APIs.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
InvalidRequest(Cow<'static, str>)
Caller supplied an invalid request before any provider was contacted — e.g. empty message list, missing required field, schema mismatch.
Config(Cow<'static, str>)
Configuration error detected at construction time (builders, factories, crate-init code).
Provider
Provider failure. kind distinguishes transport-class
failures (network / TLS / DNS) from HTTP-class failures
(4xx / 5xx) so retry classifiers can act on the typed signal
rather than parsing strings or reading a status: 0
sentinel. retry_after carries the vendor’s Retry-After
hint when present — the retry layer honours it ahead of its
own backoff (invariant #17 — vendor authoritative signal
beats self-jitter).
Fields
kind: ProviderErrorKindFailure category — Network, Tls, Dns, or
Http(status).
Cancelled
The operation was cancelled via the ExecutionContext cancellation token.
DeadlineExceeded
The operation hit the deadline carried by ExecutionContext.
Interrupted
A dispatch (tool body, graph node, or middleware layer) requested
human-in-the-loop intervention. The runtime catches this,
persists a checkpoint at the pre-dispatch state, and returns
kind + payload to the caller. Resume with
entelix_graph::CompiledGraph::resume_with.
See crate::interruption::InterruptionKind for the typed
reason taxonomy and crate::interrupt /
crate::interrupt_with for the canonical raise sites.
Fields
kind: InterruptionKindTyped reason — Custom for operator-defined pauses,
ApprovalPending { tool_use_id } for tool-approval
pauses raised by ApprovalLayer, or any future SDK
variant. Operator match sites should carry a fall-through
_ arm.
ModelRetry
A validator (typed-output OutputValidator, tool body, hook)
requested the model retry the current turn with corrective
feedback. Distinct from Self::Provider (transport
retries — wire-level failure) and Self::InvalidRequest
(operator misuse) so retry classifiers, OTel dashboards, and
budget meters all branch on a typed signal.
Catch-and-resume semantics: the surrounding agent or
complete_typed<O> loop catches this variant, appends a
RetryPromptPart to the conversation carrying hint, and
re-invokes the model — counting one increment against
ChatModelConfig::validation_retries. Operators that want to
raise this variant build it via Error::model_retry so
the RenderedForLlm funnel (invariant 16) cannot be
bypassed.
Fields
hint: RenderedForLlm<String>Corrective text the loop will surface to the model on the
retried turn. The RenderedForLlm carrier ensures the
payload was filtered through the operator-controlled
rendering funnel rather than copied raw from a
vendor-side error string.
Serde(Error)
JSON serialization or deserialization failed at an entelix-managed boundary (codec, tool I/O, persistence write/read).
Auth(AuthError)
Credential resolution or use failed. Distinct from
Self::Provider so retry policies and dashboards can
distinguish “the model is down” from “our key is bad” without
pattern-matching on error messages.
UsageLimitExceeded(UsageLimitBreach)
A RunBudget axis was exceeded — request count, token
totals, or tool calls hit the configured limit. The
axis field identifies which axis fired; limit is the
configured cap; observed is the value that breached it.
Distinct from Self::Provider so retry classifiers can
short-circuit (a budget breach does not retry) and from
Self::InvalidRequest so dashboards see the budget
signal as a first-class category.
A crate::RunBudget axis was exceeded. The typed
crate::run_budget::UsageLimitBreach enum carries both
the breaching axis and its magnitude in one variant — axis
and magnitude are paired by construction so consumers
pattern-match a single value rather than checking the axis
to know which numeric type to read.
Implementations§
Source§impl Error
impl Error
Sourcepub fn invalid_request(msg: impl Into<Cow<'static, str>>) -> Self
pub fn invalid_request(msg: impl Into<Cow<'static, str>>) -> Self
Build an InvalidRequest from a static or owned string.
Sourcepub fn config(msg: impl Into<Cow<'static, str>>) -> Self
pub fn config(msg: impl Into<Cow<'static, str>>) -> Self
Build a Config error from a static or owned string.
Sourcepub const fn model_retry(hint: RenderedForLlm<String>, attempt: u32) -> Self
pub const fn model_retry(hint: RenderedForLlm<String>, attempt: u32) -> Self
Build a Self::ModelRetry from an LLM-rendered hint. The
attempt counter starts at zero and is incremented by the
surrounding retry loop on each emit; validators / tools
raising this variant from a fresh call site pass 0 and
trust the loop to stamp the running counter.
Construction goes through crate::llm_facing::RenderedForLlm so the
hint is not a free-form String — the typed carrier ensures
the message has been routed through the operator’s rendering
funnel (invariant 16). Consumers raising this variant from a
validator typically obtain the rendered hint via
LlmRenderable::for_llm.
Sourcepub fn provider_http(status: u16, message: impl Into<String>) -> Self
pub fn provider_http(status: u16, message: impl Into<String>) -> Self
Build an HTTP-class provider error. Use the _network /
_tls / _dns variants for transport-class failures so
retry classifiers see the typed signal rather than a
stringly-typed status code.
Status 0 / 1xx / 2xx / 3xx / ≥600 do not represent a
terminal vendor response. The constructor coerces them to
ProviderErrorKind::Network so retry classifiers, wire
codes, and dashboards see “we never received a terminal
response” rather than a plausible-looking upstream_error
(invariant 15).
Synthetic-message form: use when the message is composed
from vendor body fields (no source error). For
std::error::Error-bearing failures, prefer
Self::provider_http_from which preserves the source
chain.
Sourcepub fn provider_http_from<E>(status: u16, err: E) -> Self
pub fn provider_http_from<E>(status: u16, err: E) -> Self
Build an HTTP-class provider error from any
std::error::Error. Message is err.to_string(); the
original error is preserved as #[source]. Status coercion
follows Self::provider_http — non-4xx/5xx statuses
surface as ProviderErrorKind::Network.
Sourcepub fn provider_network(message: impl Into<String>) -> Self
pub fn provider_network(message: impl Into<String>) -> Self
Build a network-class provider error (connect refused, read reset, peer hangup before HTTP framing). Distinguishes “vendor returned a 5xx” from “we never spoke to vendor”.
Synthetic-message form: use when no source error exists
(e.g. vendor wire-format prose lifted from a JSON body).
Source-bearing form: Self::provider_network_from derives
the message from the source’s Display and stores the source
for {:?} walks (preferred for map_err chains).
Sourcepub fn provider_network_from<E>(err: E) -> Self
pub fn provider_network_from<E>(err: E) -> Self
Build a network-class provider error from any
std::error::Error. Message is err.to_string(); the
original error is preserved as #[source] so operator
diagnostics walk the full chain. Pairs with .map_err:
http_req.send().await.map_err(Error::provider_network_from)?;Sourcepub fn provider_tls(message: impl Into<String>) -> Self
pub fn provider_tls(message: impl Into<String>) -> Self
Build a TLS-class provider error (handshake failure, certificate validation, protocol mismatch).
Sourcepub fn provider_tls_from<E>(err: E) -> Self
pub fn provider_tls_from<E>(err: E) -> Self
Build a TLS-class provider error from any
std::error::Error. Message is err.to_string(); the
original error is preserved as #[source].
Sourcepub fn provider_dns(message: impl Into<String>) -> Self
pub fn provider_dns(message: impl Into<String>) -> Self
Build a DNS-class provider error (name resolution failure, SSRF allowlist rejection at the resolver).
Sourcepub fn provider_dns_from<E>(err: E) -> Self
pub fn provider_dns_from<E>(err: E) -> Self
Build a DNS-class provider error from any
std::error::Error. Message is err.to_string(); the
original error is preserved as #[source].
Sourcepub fn with_retry_after(self, duration: Duration) -> Self
pub fn with_retry_after(self, duration: Duration) -> Self
Attach a Retry-After duration to a provider error. The
duration arrives from the vendor’s Retry-After response
header (or equivalent body field). Returns self unchanged
for non-Provider variants — callers know the variant they
constructed, so this is Self -> Self rather than a typed
projection.
Sourcepub fn with_source<E>(self, err: E) -> Self
pub fn with_source<E>(self, err: E) -> Self
Attach the underlying error as the Provider variant’s source
chain, preserving root-cause context for operator diagnostics
({:?} / std::error::Error::source walk). Returns self
unchanged for non-Provider variants.
Channel-separation guarantee (invariant 16): the source chain
is operator-only. crate::LlmRenderable::render_for_llm
strips it for LLM-facing renderings; sinks / OTel / logs keep
the full diagnostic.
Sourcepub fn envelope(&self) -> ErrorEnvelope
pub fn envelope(&self) -> ErrorEnvelope
Typed wire shape for this error — the single canonical
inspector integrators read at sink / SSE / audit boundaries
instead of parsing Display output. ErrorEnvelope is Copy,
so call sites cache or pass-by-value without ceremony.
Guarantees (patch-version stable, mirrored on ErrorEnvelope’s
own doc-comment):
wire_codeis a snake-case ASCII&'static strsuitable as an i18n key, metric label, or typed-wire-envelope key. Adding a newErrorvariant adds a new code; existing codes are forever-stable.wire_classis the coarse responsibility split (Clientfor caller-actionable failures,Serverfor SDK/vendor-side failures). Orthogonal to retryability.retry_after_secscarries the vendor’sRetry-Afterhint converted to whole seconds when the originatingSelf::Providererror captured one;Nonefor every other variant or Provider error without a hint.provider_statuscarries the raw HTTP status when the error isProviderwithProviderErrorKind::Http;Noneotherwise. Lets sinks/audit retain429 vs 503granularity even thoughwire_codecollapses them onto coarse buckets.
HTTP provider failures bucket on the status family for
wire_code so vendor drift (a new 4xx) absorbs into the right
class without an SDK release; the raw status is still observable
through provider_status for operators that want the exact
signal.
Trait Implementations§
Source§impl Error for Error
impl Error for Error
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl LlmRenderable<String> for Error
impl LlmRenderable<String> for Error
Source§fn render_for_llm(&self) -> String
fn render_for_llm(&self) -> String
Short, model-actionable rendering. Mapping:
InvalidRequest(msg)→"invalid input: {msg}"— the message is already caller-supplied and free of vendor identifiers.Provider { .. }→"upstream model error"— vendor status is operator-only.Auth(_)→"authentication failed"— never echo the underlying provider’s auth diagnostic.Config(_)→"tool misconfigured"— operator must fix.Cancelled→"cancelled".DeadlineExceeded→"timed out".Interrupted { .. }→"awaiting human review".Serde(_)→"output could not be serialised"— the inner serde error names internal types.
Source§fn for_llm(&self) -> RenderedForLlm<T>
fn for_llm(&self) -> RenderedForLlm<T>
Self::render_for_llm’s output.
External crates that implement this trait cannot override
this method without access to RenderedForLlm::new, which
is pub(crate) to entelix-core. The boundary therefore
holds across crate boundaries: only entelix-core’s default
impl can produce a RenderedForLlm<T>.