Skip to main content

ClientError

Enum ClientError 

Source
#[non_exhaustive]
pub enum ClientError {
Show 15 variants Http(HttpError), InvalidHeaderValue(InvalidHeaderValueError), AuthFailed(u16), Parse(ParseError), BlobIntegrityMismatch { expected: String, actual: String, }, InvalidArgument(String), InvalidSession(String), MethodNotFound(String), MethodError { error_type: String, description: Option<String>, }, Serialize(SerializeError), SseFrameTooLarge { limit: usize, }, ResponseTooLarge { actual: u64, limit: u64, }, WebSocket(WebSocketError), UnexpectedResponse(String), RateLimited { retry_after: UTCDate, },
}
Expand description

Errors produced by the base JMAP client.

Variants cover transport failures (Http, WebSocket), authentication (AuthFailed), JMAP protocol errors (MethodError, UnexpectedResponse), caller bugs (InvalidArgument, InvalidHeaderValue, Serialize), and resource-exhaustion guards (ResponseTooLarge, SseFrameTooLarge).

Marked #[non_exhaustive] so additional variants may be introduced in minor releases. See per-variant documentation for retriability guidance.

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

Http(HttpError)

Network or TLS error from the HTTP layer. May be retriable (transient network failure) or permanent (TLS configuration error). Indicates a network or transport problem, not a JMAP protocol error.

The payload is an opaque HttpError that does not expose any third-party error type — this crate’s HTTP transport can be swapped or its major version bumped without affecting downstream callers. Use HttpError::is_timeout, HttpError::status, etc. to diagnose.

§

InvalidHeaderValue(InvalidHeaderValueError)

A header value could not be encoded. Indicates a caller bug — the credential string contains characters that are not valid HTTP header value characters. Not retriable.

§

AuthFailed(u16)

The server returned HTTP 401 (authentication failure) or 403 (authorization failure — credentials present but insufficient). Not retriable without correcting credentials.

§

Parse(ParseError)

A server response could not be parsed or did not match the expected shape. Indicates the server sent a malformed response. Not retriable without a server fix.

The payload is an opaque ParseError that does not expose the underlying JSON parser’s error type — the variant is insulated from a future parser swap. Construct explicitly: .map_err(ClientError::from_parse) (or .map_err(jmap_base_client::ClientError::from_parse) from outside the crate). Pattern-match via ClientError::Parse(e) => e.line(), e.column(), e.classify() — see ParseError.

§

BlobIntegrityMismatch

Blob SHA-256 mismatch on upload or download. Indicates in-transit corruption or a misbehaving server. Not retriable without re-fetching metadata.

§Field semantics across both call sites (bd:JMAP-6r7c.10)

The same variant is emitted from both upload and download paths and the role of each field is constant across paths:

  • expected is the pre-stated digest the client was comparing against — i.e. the value that should hold if the bytes are intact.
  • actual is the freshly-observed digest the client just computed or just learned.

The source of each value depends on which call produced the error:

Call siteexpectedactual
JmapClient::upload_blobclient’s own SHA-256 of the bytes about to be uploadedserver’s reported SHA-256 in the upload response
JmapClient::download_blobDownloadBlobParams::expected_sha256 supplied by the caller (typed jmap_cid_types::Sha256, guaranteed canonical lowercase)client’s SHA-256 of the actually-received bytes

Both digests are canonical 64-character lowercase hex (per draft-atwood-jmap-cid-00 §2 ABNF).

Fields

§expected: String

Pre-stated SHA-256 hex digest the client was comparing against. On upload, this is the client’s own pre-upload computation; on download, this is the caller-supplied DownloadBlobParams::expected_sha256 (typed jmap_cid_types::Sha256, guaranteed canonical lowercase).

§actual: String

Freshly-observed SHA-256 hex digest. On upload, this is the server-reported digest from the upload response. On download, this is the client’s own digest over the received bytes.

§

InvalidArgument(String)

A caller-supplied argument violates a precondition (e.g. empty token, colon in BasicAuth username, missing required filter field).

§

InvalidSession(String)

The JMAP Session object from the server was missing a required field. Indicates a server-side bug or incompatible server. Not retriable.

§

MethodNotFound(String)

The JMAP API response did not contain the expected method call ID. Indicates a server-side bug or unexpected response shape.

§

MethodError

The JMAP server returned a method-level error object (RFC 8620 §3.6). Retriability depends on error_type (e.g. serverFail may be retried; invalidArguments is not retriable).

description is None when the server omits the optional description field.

Fields

§error_type: String

The type field of the JMAP method-level error object (RFC 8620 §3.6.2), e.g. "invalidArguments", "serverFail", "accountNotFound".

§description: Option<String>

Optional human-readable error description (RFC 8620 §3.6.2); None when the server omits this field.

§

Serialize(SerializeError)

A JMAP request could not be serialized to JSON when sending over WebSocket. Indicates a caller bug — the data structure contains non-serializable values. Not retriable.

This error is only returned by WsSession::send_request; the HTTP call() path delegates serialization to reqwest, which surfaces serialization failures as ClientError::Http.

The payload is an opaque SerializeError that does not expose the underlying JSON serializer’s error type. Construct explicitly: .map_err(ClientError::from_serialize). Pattern-match via ClientError::Serialize(e) => e.line(), e.column(), e.classify() — see SerializeError.

§

SseFrameTooLarge

An SSE frame exceeded the configured buffer limit (ClientConfig::max_sse_frame). The stream is terminated after this error. Indicates a misbehaving or hostile server.

Fields

§limit: usize

The configured per-frame buffer cap (in bytes) that was exceeded.

§

ResponseTooLarge

A server response body exceeded the enforced size limit. Protects against unbounded memory allocation from malicious or buggy servers. actual is in bytes (from Content-Length or actual read size).

Fields

§actual: u64

Observed response size in bytes (from Content-Length or the running total of bytes read so far when streaming).

§limit: u64

Configured maximum response size in bytes.

§

WebSocket(WebSocketError)

A WebSocket transport error (connection, framing, or TLS). May be retriable (transient network failure) or permanent (TLS config error).

The payload is an opaque WebSocketError that does not expose any third-party error type — see HttpError for the same SemVer rationale. Use WebSocketError::is_io, WebSocketError::is_protocol, etc. to diagnose.

§

UnexpectedResponse(String)

The server returned a response that violates the JMAP protocol (outside the Session fetch path). Examples: wrong Content-Type on an SSE connection, unexpected response shape on a non-session endpoint.

Distinct from ClientError::InvalidSession, which indicates a problem with the Session document itself. Not retriable without a server fix.

§

RateLimited

Server rate-limited the request. retry_after indicates when to retry.

§⚠ Not currently produced by this crate (bd:JMAP-6lsm.3, bd:JMAP-6r7c.33)

HTTP 429 responses fall through reqwest::error_for_status() and surface as ClientError::Http today, NOT as ClientError::RateLimited. A caller that matches only on this variant will miss every actual 429 from the base crate. Until bd:JMAP-6lsm.3 lands the native 429 → RateLimited conversion, callers MUST handle both cases:

match err {
    ClientError::RateLimited { retry_after } => {
        // Eventually the only path; today only produced by extension
        // crates that wrap this crate's error conversion.
        sleep_until(retry_after).await;
    }
    ClientError::Http(http) if http.status() == Some(429) => {
        // Base-crate path today (bd:JMAP-6lsm.3 will collapse this
        // into the RateLimited arm above).
        sleep(Duration::from_secs(30)).await; // or parse Retry-After
    }
    other => { /* propagate */ }
}

§Why the variant ships anyway

The variant is part of the public contract so:

  1. Extension crates that wrap or replace this crate’s transport may detect 429 + parse Retry-After themselves and produce RateLimited from their own error-conversion code.
  2. Callers that want to handle rate limiting via this typed variant have a stable target to match on, even before the conversion logic lands here (tracked under bd:JMAP-6lsm.3).

The variant shape will not change in a backward-incompatible way when 429 → RateLimited conversion lands — it is part of a #[non_exhaustive] enum and the struct payload is itself stable, so callers writing the dual-match pattern above today will not need to adjust when the migration completes.

Fields

§retry_after: UTCDate

Absolute UTC instant the client should wait until before retrying, parsed from the Retry-After HTTP header (RFC 9110 §10.2.3).

Implementations§

Source§

impl ClientError

Source

pub fn from_parse(e: Error) -> Self

Convert a serde_json::Error from a deserialize / parse step into a ClientError::Parse variant carrying an opaque ParseError payload (bd:JMAP-6r7c.26).

Public because extension client crates (jmap-mail-client, jmap-chat-client, etc.) need to surface their own JSON parse failures as ClientError::Parse. Use in .map_err:

let val: T = serde_json::from_slice(&bytes)
    .map_err(jmap_base_client::ClientError::from_parse)?;

A future JSON-parser swap would deprecate this constructor in favor of an analogous one for the new parser; the variant payload type (ParseError) stays stable.

Source

pub fn from_serialize(e: Error) -> Self

Convert a serde_json::Error from a serialize step into a ClientError::Serialize variant carrying an opaque SerializeError payload (bd:JMAP-6r7c.26).

Public for the same reason as from_parse.

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

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<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> 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> Same for T

Source§

type Output = T

Should always be Self
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> ToStringFallible for T
where T: Display,

Source§

fn try_to_string(&self) -> Result<String, TryReserveError>

ToString::to_string, but without panic on OOM.

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