Skip to main content

ModelError

Enum ModelError 

Source
pub enum ModelError {
    Unreachable {
        model: ModelId,
        detail: String,
    },
    Refused {
        model: ModelId,
        detail: String,
    },
    Egress {
        model: ModelId,
        detail: String,
    },
    RateLimited {
        model: ModelId,
        detail: String,
        retry_after: Option<u64>,
    },
    Interrupted {
        model: ModelId,
        usage: Usage,
        detail: String,
    },
    Unavailable {
        model: ModelId,
        detail: String,
    },
    Unaccounted {
        model: ModelId,
        detail: String,
    },
    Unusable {
        model: ModelId,
        usage: Usage,
        detail: String,
    },
}
Expand description

Why a completion failed.

Variants§

§

Unreachable

Never reached the provider.

Fields

§model: ModelId
§detail: String
§

Refused

The provider refused before generating: bad request, unknown model, a content filter on the input. Nothing was metered.

Fields

§model: ModelId
§detail: String
§

Egress

This plane refused to connect: the driver’s host is not one the deployment’s Egress allowlist grants.

Distinct from Refused, which says the provider declined. Both are DidNotHappen and neither spends a retry attempt, so the distinction buys no different recovery — it buys the operator the right half of the system to go and look at. Reported as a provider refusal, an egress misconfiguration sends somebody to a vendor’s status page.

Fields

§model: ModelId
§detail: String
§

RateLimited

Rate-limited before generating.

Separate from Refused because the response is different: this one is worth retrying, and it is the one case here where retrying is unambiguously safe.

retry_after is the provider’s own Retry-After, in seconds, when it named one. Carried rather than discarded because the window it names is the only number that makes retrying useful: a computed backoff measured in hundreds of milliseconds spends every permitted attempt inside a window measured in tens of seconds, and reports the provider as down.

Fields

§model: ModelId
§detail: String
§retry_after: Option<u64>
§

Interrupted

It generated, and then the stream died.

The expensive case. The tokens counted here have been spent whatever happens next.

Fields

§model: ModelId
§usage: Usage
§detail: String
§

Unavailable

It reached the provider, and nothing came back that says whether it generated.

A non-streaming 5xx, or a response that could not be read. The honest position is that this is unknowable from here, and both guesses are wrong in a different way: calling it Interrupted makes a transient blip fatal, and calling it free lets a retry loop spend real money against a ceiling that reads zero.

Treated as safe to repeat, because a completion does not change the world — so repeating is a correctness no-op and only a cost. The documented price is that the spend ceiling may under-count by at most one call per occurrence.

A driver that can see partial usage must report Interrupted instead — which is what both shipped drivers do when streaming, and why they stream by default. Where the provider makes even that impossible, the answer is Unaccounted, not this.

Fields

§model: ModelId
§detail: String
§

Unaccounted

It generated, the stream died, and the cost is unknowable.

The state OpenAI’s Responses stream can produce and Anthropic’s cannot. Usage appears there only in the terminal event, so a connection cut after four hundred tokens of deltas leaves the driver certain that generation happened and ignorant of what it cost.

Neither neighbour says that, which is why this variant exists rather than being folded into one of them:

  • Unavailable means it may never have generated, and is therefore safe to repeat. Here we watched it generate; asking again buys a second bill for the same question.
  • Interrupted carries a Usage, and filling it with zeroes is the “guess free” failure this crate refuses everywhere else — it reads as this cost nothing rather than as nobody knows.

So it is Disposition::Landed with no usage, and the under-count is admitted rather than hidden: the budget will be short by whatever this call generated. What the variant buys is that the runtime stops paying twice for it. A caller who needs the true figure has the provider’s response id and a Recovery policy to reconcile with; a driver quietly making a second unjournaled request to find out is not the answer.

Fields

§model: ModelId
§detail: String
§

Unusable

It answered, and the answer was not usable — truncated JSON, a refusal where a tool call was required. Metered, because it generated.

Fields

§model: ModelId
§usage: Usage
§detail: String

Implementations§

Source§

impl ModelError

Source

pub const fn disposition(&self) -> Disposition

What this failure says about whether the call reached the provider.

Source

pub const fn usage(&self) -> Usage

What was consumed before the failure.

Enumerated rather than defaulted, because the default is free and this is what the token and cost ceilings are computed from. A variant added later that carries a usage would compile, pass every test here, and report nothing consumed — which is the direction the ceilings exist to prevent. Unaccounted reports zero deliberately and says so on its own documentation: what is unknown there is the amount, not whether it happened, and its disposition already carries the latter.

Trait Implementations§

Source§

impl Debug for ModelError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for ModelError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for ModelError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<Unshared, Shared> IntoShared<Shared> for Unshared
where Shared: FromUnshared<Unshared>,

Source§

fn into_shared(self) -> Shared

Creates a shared type from an unshared type.
Source§

impl<T> MaybeSend for T
where T: Send,

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToSmolStr for T
where T: Display + ?Sized,

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more