Skip to main content

Error

Enum Error 

Source
#[non_exhaustive]
pub enum Error {
Show 15 variants InvalidData { message: String, }, Protocol { status: NtStatus, command: Command, }, Auth { message: String, }, Io(Error), Timeout, Disconnected, ReconnectFailed { attempts: u32, waited: Duration, cause: ErrorKind, reason: String, }, DurableHandleLost { path: String, reason: DurableLoss, }, DfsReferralRequired { path: String, }, Cancelled, SessionExpired, FileTooLargeForSingleRead { size: u64, requested: u32, }, CreditStarvation { needed: u16, available: u16, waited: Duration, }, SendTimeout { command: Command, bytes: usize, waited: Duration, }, ServerUnresponsive { silent_for: Duration, },
}
Expand description

Top-level error type for SMB2 operations.

#[non_exhaustive]: new variants appear as the crate learns to tell more failures apart, so match on it with a _ arm, or branch on Error::kind instead. Adding a variant is not treated as a breaking change.

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

InvalidData

The data is malformed or does not match the expected format.

Fields

§message: String

Description of what went wrong.

§

Protocol

The server returned a non-success NTSTATUS.

Fields

§status: NtStatus

The NTSTATUS code from the response header.

§command: Command

The command that triggered the error.

§

Auth

Authentication failed.

Fields

§message: String

Description of what went wrong.

§

Io(Error)

An I/O or transport error occurred.

§

Timeout

The operation timed out.

§

Disconnected

The connection was lost.

§

ReconnectFailed

Bringing a dead connection back on a fresh socket did not work.

Every attempt failed, or the whole revival ran past ReconnectPolicy::total_budget, or a revival failed recently enough that its verdict still stands (see ReconnectPolicy::failure_cooldown).

The connection is dead and stays dead. Branch on cause to tell “the credentials are wrong now, ask the user” from “the network is down, try again later”; reason is display text for a human and ❌ must never be matched on. Classifies as ErrorKind::ConnectionLost and reports as retryable — the connection is finished, but the work usually is not, and re-running the file on a fresh client is the intended response.

Fields

§attempts: u32

Dials made before giving up.

§waited: Duration

Wall clock spent trying.

§cause: ErrorKind

What the last attempt failed with, as a typed classification.

§reason: String

The last failure rendered for a human. Display only.

§

DurableHandleLost

A durable handle could not be claimed back after a reconnect, so the interrupted transfer has to restart rather than resume.

Never a data-safety failure: it is what the client returns instead of guessing. Branch on reason to tell an expired open (routine) from a server that handed back the wrong file (alarming, and logged at error!). Whatever the reason, the response is the same: reopen the file and write it from the start. Classifies as ErrorKind::ConnectionLost and reports as retryable.

Fields

§path: String

The path the handle was opened at.

§reason: DurableLoss

Which guarantee did not hold.

§

DfsReferralRequired

The path requires DFS referral resolution.

The server returned STATUS_PATH_NOT_COVERED, meaning this path lives on a different server via DFS. The caller can query for a referral or display a helpful message.

Fields

§path: String

The path that needs DFS resolution.

§

Cancelled

The operation was cancelled by the caller (via progress callback).

§

SessionExpired

The session expired and reauthentication failed.

The pipeline normally handles STATUS_NETWORK_SESSION_EXPIRED transparently by reauthenticating. This error surfaces only when reauthentication itself fails.

§

FileTooLargeForSingleRead

The file is larger than the single READ that was issued for it, so returning what came back would truncate it.

Returned by Tree::read_file, Tree::read_file_compound, and Tree::read_file_compound_sized. Those paths issue one READ, so a file bigger than that READ asked for can’t come back whole; rather than silently dropping the tail, they fail with this. The two ways to hit it:

  • The file exceeds the server’s negotiated per-READ maximum (MaxReadSize), which is as small as 64 KiB on some servers.
  • The file outgrew the expected_size handed to read_file_compound_sized between the caller’s scan and the read.

size is the server’s authoritative size from the same round-trip. Retrying read_file_compound_sized with it fixes the second case only, where size still fits one READ. When requested is already the server’s MaxReadSize the retry asks for the same bytes and fails the same way; Tree::read_file_pipelined reads any size in a sliding window of chunked READs and always works. Classifies as ErrorKind::TooLarge.

Fields

§size: u64

The file’s size in bytes, as the server reported it.

§requested: u32

The number of bytes that single READ asked for, which is what bounds how much it could have returned. At most the server’s MaxReadSize, and less when the caller supplied a smaller expected_size.

§

CreditStarvation

The server stopped granting credits, so the request could not be sent.

Every SMB2 request spends credits from a budget the server grants and replenishes on each response. This crate never sends beyond that budget (doing so is a protocol violation the server may answer by dropping the connection, or — on some NAS firmware — by going silent). When the budget runs dry the send waits for a grant; this error says the wait ran out.

In practice it means the server has stopped answering while the TCP connection is still up, so treat it as a dead connection: reconnect. Classifies as ErrorKind::TimedOut and reports as retryable.

Tune the wait with Connection::set_credit_wait_timeout.

Fields

§needed: u16

Credits the request needed (its CreditCharge).

§available: u16

Credits on hand when the wait was abandoned.

§waited: Duration

How long the send waited for a grant.

§

SendTimeout

A request could not be handed to the network in time.

This is the send side, not the response side: the bytes never reached the socket. A socket that stops accepting writes while TCP stays ESTABLISHED produces this, and so does a queue behind one such write.

The distinction from Error::Timeout matters when reading logs. A Timeout means the server was asked and said nothing; a SendTimeout means the server was never asked, so nothing about the server can be inferred from it. A 2026-08-01 wedge was misread as server silence for exactly this reason: ~700 requests sat registered as in-flight with zero bytes on the wire.

The connection is torn down when this fires: a write abandoned partway leaves half a frame on the wire, so the stream can’t be trusted again. Classifies as ErrorKind::TimedOut and reports as retryable.

Tune with Connection::set_send_timeout.

Fields

§command: Command

The command that was being sent (the first sub-op of a compound).

§bytes: usize

Size of the frame that could not be written.

§waited: Duration

How long the send waited, queue time included.

§

ServerUnresponsive

A request ran out of deadline on a connection the server had gone completely silent on, so the whole session was declared dead.

This is Error::Timeout with a second fact attached. Both mean a request went unanswered for its full budget; this one adds that the server put nothing on the wire in the meantime, not even an answer to the SMB2 ECHO probes the keepalive sends (MS-SMB2 § 2.2.28, a request that touches no disk and no share). One stuck operation cannot look like that, so the connection is torn down and every other waiter is told at once rather than sitting out its own deadline one by one.

The distinction from the other three is what it lets you conclude:

  • Error::Timeoutthis request went unanswered. The connection may be perfectly healthy and the operation merely stuck; retrying it on the same connection is reasonable.
  • Error::SendTimeout – the request never reached the network, so nothing at all follows about the server.
  • Error::Disconnected – the socket itself went away (EOF, reset).
  • ServerUnresponsive – the socket is up and the server is answering nothing at all. Reconnect; retrying on this connection can only fail.

Classifies as ErrorKind::ConnectionLost (the same as Disconnected, so existing reconnect paths pick it up unchanged) and reports as retryable. It cannot occur with the keepalive off (Connection::set_keepalive), since nothing would then be asking: expect Error::Timeout instead.

Fields

§silent_for: Duration

How long since the server last put any frame on the wire.

Implementations§

Source§

impl Error

Source

pub fn invalid_data(msg: impl Into<String>) -> Self

Create an InvalidData error with the given message.

Source

pub fn is_retryable(&self) -> bool

Returns true if this error is potentially transient and the operation could succeed on retry.

Source

pub fn status(&self) -> Option<NtStatus>

Returns the NTSTATUS code if this is a protocol error.

Source§

impl Error

Source

pub fn kind(&self) -> ErrorKind

Classify this error into a high-level category.

Consumers can match on ErrorKind without understanding raw NTSTATUS codes. For the underlying status code, use status().

Trait Implementations§

Source§

impl Debug for Error

Source§

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

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

impl Display for Error

Source§

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

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

impl Error for Error

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

impl From<Error> for Error

Source§

fn from(source: Error) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl !RefUnwindSafe for Error

§

impl !UnwindSafe for Error

§

impl Freeze for Error

§

impl Send for Error

§

impl Sync for Error

§

impl Unpin for Error

§

impl UnsafeUnpin for Error

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