Skip to main content

ClientError

Enum ClientError 

Source
#[non_exhaustive]
pub enum ClientError { Transport { command: String, source: Box<Error>, }, Cluster { command: String, code: i64, message: String, raw: String, }, Http { command: String, status: u16, body: String, }, Redirected { command: String, status: u16, location: String, refusal: RedirectRefusal, heavy: bool, }, Decode { command: String, reason: String, }, ResponseTooLarge { command: String, limit: u64, }, BatchInterrupted { answered: Vec<Result<YsonValue>>, parts: usize, cause: Box<ClientError>, }, Io { path: String, source: Error, }, OperationFailed { id: String, state: String, error: Option<String>, jobs: Vec<JobFailure>, }, NotAWorker { path: String, reason: String, }, Config(String), }
Expand description

Something went wrong talking to the cluster.

Non-exhaustive. A match over this must carry a _ arm: the ways a cluster can refuse are the cluster’s to add, not this crate’s to freeze, and every release so far has added one. Naming a variant, constructing one and destructuring one all work as before.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Transport

The request could not be made, or the connection failed.

Fields

§command: String

The API command being attempted.

§source: Box<Error>

The underlying HTTP error.

§

Cluster

The cluster reported an error.

YTsaurus returns a structured error in the X-YT-Error header; the message and code are lifted out of it so the common case reads well, and the whole thing is kept in raw because the nested inner_errors are often where the real cause is.

Fields

§command: String

The API command that failed.

§code: i64

YTsaurus error code.

§message: String

Top-level error message.

§raw: String

The full error document, as returned.

§

Http

The cluster answered with an unexpected HTTP status and no usable error.

Fields

§command: String

The API command that failed.

§status: u16

The HTTP status returned.

§body: String

Whatever body came back, truncated.

§

Redirected

A redirect was refused rather than followed.

A control proxy does not refuse a heavy read: it answers 307 Temporary Redirect naming a data proxy on another host — the HTTP proxy reference gives that row as “307 | Redirecting heavy queries from light to heavy proxies”. Following it without the Authorization header — which is what ureq does by default — makes the request arrive unauthenticated, and the cluster then reports Client is missing credentials about a token that may be perfectly valid. Re-attaching it and going would follow an instruction the client never asked for, on a request already addressed elsewhere. This error is the third answer: go nowhere, and say where the proxy pointed.

The message stops short of declaring the token good. It cannot know that — a gateway in front of the cluster may answer an expired token with a redirect of its own — so it reports the one thing this client is certain of: the credentials never reached the host that answered.

Not every redirect ends here. One that stays on the origin the request was addressed to is followed, credentials and all, because nothing new learns the token by it; refusal says which rule this redirect met.

Fields

§command: String

The API command that was redirected.

§status: u16

The redirect status the proxy answered with — 307 in practice.

§location: String

Where it pointed, resolved against the address the request went to, so a relative Location still names a host. Usually a data proxy on a different one.

§refusal: RedirectRefusal

Which rule the redirect met.

§heavy: bool

Whether the redirected command reads or writes a data stream.

Only those belong on a heavy proxy, so only those are told to go to one: a create that met a balancer’s 301 cannot use that advice and is not given it.

§

Decode

A response could not be decoded.

Fields

§command: String

The API command whose response was unreadable.

§reason: String

What went wrong.

§

ResponseTooLarge

A buffered response ran past what this client will hold in memory.

Its own variant rather than a ClientError::Decode, which is what it was first written as. Every other Decode in this crate means the bytes were read and were not the shape expected — a YSON document that does not parse, a Skiff frame that ends early, an envelope missing the key the command answers under. This body was never read at all, and the difference is the whole of what the caller can do next: a Decode invites a look at the data, and this invites the streaming half of the same command, which the message names.

Refused rather than truncated, and never retried — no amount of waiting shrinks a response, and the host that served it did nothing wrong. That second half is not this caller’s concern alone: a heavy read blamed on its host takes a healthy data proxy out of the pool, and enough of them empty it. See http::body_failure.

limit counts bytes after decompression, which is where they are actually held — and it is what this client holds, not what the process needs: the buffer grows by doubling and copies, so peak residency runs above the number. See http::RESPONSE_LIMIT.

Fields

§command: String

The API command whose response was too large.

§limit: u64

The ceiling it ran past, in decoded bytes.

§

BatchInterrupted

A split batch stopped part of the way through, and the requests before the failure have already run on the cluster.

Client::execute_batch sends a batch larger than BatchRequest::with_max_part_size as several execute_batch requests. There is no rollback: when a later request fails wholesale, the earlier ones have run and whichever of their parts succeeded have taken effect. Reporting only the failure would hide that, and re-running the same BatchRequest is not a recovery either — a second execution mints fresh mutation ids, so the parts that already landed are applied a second time rather than deduplicated.

So the prefix comes back with the failure: answered holds one entry per part of every request that completed, in part order, with exactly the per-part Ok/Err split Client::execute_batch would have handed back. answered.len() is where the batch stopped, and parts is how many there were, so the parts never attempted are batch[answered.len()..].

Only for a batch that was split: a batch that fits in one request fails with the underlying error itself, since there is no prefix to report. Put the sequence in a transaction, or keep it inside one request, if a partial application is not something the caller can act on.

The rendered message says the same thing, deliberately. It is the sentence that reaches a log line and an unwrap() panic, so it must not draw a line the cluster does not honour: answered.len() is where the answers stop, not where the effects stop. The request that failed runs its parts whatever it answers — measured — and answered itself holds Err entries, which applied nothing at all.

Fields

§answered: Vec<Result<YsonValue>>

The parts already answered, in part order — every part of every request that completed, Ok and Err alike.

§parts: usize

How many parts the batch held in all.

§cause: Box<ClientError>

Why the rest never went.

§

Io

Reading a local file failed.

Fields

§path: String

The path that could not be read.

§source: Error

The underlying I/O error.

§

OperationFailed

An operation finished in a state other than completed.

Fields

§id: String

The operation’s ID.

§state: String

Its terminal state — failed, aborted, …

§error: Option<String>

The operation’s error document, when it has one.

§jobs: Vec<JobFailure>

The jobs that failed, with what they printed.

Empty if the cluster reported none, if job diagnostics are turned off (see Client::with_job_diagnostics), or if asking for them failed — collecting them must never replace the failure being reported.

§

NotAWorker

A binary that a cluster node could not run was about to be uploaded.

Fields

§path: String

The binary that was refused.

§reason: String

What is wrong with it, and what to do instead.

§

Config(String)

The environment did not describe a cluster to talk to.

Trait Implementations§

Source§

impl Debug for ClientError

Source§

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

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

impl Display for ClientError

Source§

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

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

impl Error for ClientError

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<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> 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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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<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