leptos-rs/leptos · error
At {caller}, you call `to_server_error()` or use `server_fn_
Error message
At {caller}, you call `to_server_error()` or use `server_fn_error!` with a value that does not implement `Clone` and either `Error` or `Display`. What it means
server_fn's error conversion trait ViaError only accepts error types that are Clone plus either Error or Display; the blanket fallback impl for WrapError exists only to produce a compile-targeted panic via #[track_caller]. Hitting it means to_server_error() (or the server_fn_error! macro) was invoked at runtime with a value that fails those trait bounds in the chosen conversion path.
Source
Thrown at server_fn/src/error.rs:150
fn to_server_error(&self) -> ServerFnError<E> {
ServerFnError::WrappedServerError(self.0.clone())
}
}
// If it doesn't impl Error, but does impl Display and Clone,
// we can still wrap it in String form
impl<E: Display + Clone> ViaError<E> for &WrapError<E> {
fn to_server_error(&self) -> ServerFnError<E> {
ServerFnError::ServerError(self.0.to_string())
}
}
// This is what happens if someone tries to pass in something that does
// not meet the above criteria
impl<E> ViaError<E> for WrapError<E> {
#[track_caller]
fn to_server_error(&self) -> ServerFnError<E> {
panic!(
"At {}, you call `to_server_error()` or use `server_fn_error!` \
with a value that does not implement `Clone` and either `Error` \
or `Display`.",
std::panic::Location::caller()
);
}
}
/// A type that can be used as the return type of the server function for easy error conversion with `?` operator.
/// This type can be replaced with any other error type that implements `FromServerFnError`.
///
/// Unlike [`ServerFnErrorErr`], this does not implement [`Error`](trait@std::error::Error).
/// This means that other error types can easily be converted into it using the
/// `?` operator.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)View on GitHub (pinned to 32d20f6c9d)
Solutions
- Make the error type implement Clone and either std::error::Error or Display (derive Clone, thiserror::Error, and Display).
- Ensure the error type does not contain non-Clone fields; wrap them in Arc or convert to a String.
- Use the From-based conversion path expected by the server function's custom error type instead of relying on WrapError's fallback.
- Check the #[server] function's error type parameter matches a type implementing the required traits.
Example fix
// before
struct ApiError { inner: ReqwestError } // not Clone -> falls into panic impl
// after
#[derive(Debug, Clone, thiserror::Error)]
enum ApiError {
#[error("request failed: {0}")]
Request(String), // Clone + Display + Error
} Defensive patterns
Strategy: type-guard
Validate before calling
fn valid_server_fn_error<E: Clone + std::fmt::Display>(_e: &E) {} // compile-time check before using server_fn_error! Type guard
fn is_convertible_error<E: Clone + std::fmt::Display + std::error::Error>(_e: &E) -> bool { true } // bounds act as the guard Try / catch
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| err.to_server_error()));
Prevention
- Derive Clone + thiserror::Error on all custom server-function error types.
- Avoid non-Clone fields (boxed dyn errors, handles) in error enums; use Arc or String.
- Add a unit test calling to_server_error on each error variant to catch the fallback impl at test time.
When it happens
Trigger: Calling .to_server_error() on a wrapped error type, or using server_fn_error!/WrapError in a server function whose custom error type E does not implement Clone together with std::error::Error or Display, so the fallback impl is selected.
Common situations: Defining a custom ServerFnErrorErr/error type missing Clone or Display; returning non-cloneable error types (e.g. containing a Box<dyn Error> or a reqwest::Error) from server functions; type inference silently choosing the ViaError fallback impl after refactoring the error type.
Related errors
- {location:?} expected context of type {type_name:?} to be pr
- Tried to access a reactive value that has already been dispo
- could not find key for index {index:?} at {caller}
- <FlatRoutes> should not be used with nested routes.
- internal error: entered unreachable code
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/d2bbaa5e37887ac6.
Report an issue: GitHub.