{"record":{"id":"d2bbaa5e37887ac6","repo":"leptos-rs/leptos","slug":"at-caller-you-call-to-server-error-or-use","errorCode":null,"errorMessage":"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`.","messagePattern":"At (.+?), you call `to_server_error\\(\\)` or use `server_fn_error!` with a value that does not implement `Clone` and either `Error` or `Display`\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server_fn/src/error.rs","lineNumber":150,"sourceCode":"    fn to_server_error(&self) -> ServerFnError<E> {\n        ServerFnError::WrappedServerError(self.0.clone())\n    }\n}\n\n// If it doesn't impl Error, but does impl Display and Clone,\n// we can still wrap it in String form\nimpl<E: Display + Clone> ViaError<E> for &WrapError<E> {\n    fn to_server_error(&self) -> ServerFnError<E> {\n        ServerFnError::ServerError(self.0.to_string())\n    }\n}\n\n// This is what happens if someone tries to pass in something that does\n// not meet the above criteria\nimpl<E> ViaError<E> for WrapError<E> {\n    #[track_caller]\n    fn to_server_error(&self) -> ServerFnError<E> {\n        panic!(\n            \"At {}, you call `to_server_error()` or use  `server_fn_error!` \\\n             with a value that does not implement `Clone` and either `Error` \\\n             or `Display`.\",\n            std::panic::Location::caller()\n        );\n    }\n}\n\n/// A type that can be used as the return type of the server function for easy error conversion with `?` operator.\n/// This type can be replaced with any other error type that implements `FromServerFnError`.\n///\n/// Unlike [`ServerFnErrorErr`], this does not implement [`Error`](trait@std::error::Error).\n/// This means that other error types can easily be converted into it using the\n/// `?` operator.\n#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]\n#[cfg_attr(\n    feature = \"rkyv\",\n    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/leptos-rs/leptos/blob/32d20f6c9d517451d77beb68d88c7716823dac41/server_fn/src/error.rs#L132-L168","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nstruct ApiError { inner: ReqwestError } // not Clone -> falls into panic impl\n\n// after\n#[derive(Debug, Clone, thiserror::Error)]\nenum ApiError {\n    #[error(\"request failed: {0}\")]\n    Request(String), // Clone + Display + Error\n}","handlingStrategy":"type-guard","validationCode":"fn valid_server_fn_error<E: Clone + std::fmt::Display>(_e: &E) {} // compile-time check before using server_fn_error!","typeGuard":"fn is_convertible_error<E: Clone + std::fmt::Display + std::error::Error>(_e: &E) -> bool { true } // bounds act as the guard","tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| err.to_server_error()));","preventionTips":["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."],"tags":["leptos","server-fn","server-fn-error","trait-bounds","panic"],"backgroundTag":"server-fn-error-conversion","analyzedSha":"32d20f6c9d517451d77beb68d88c7716823dac41","analyzedAt":"2026-09-01T18:55:42.580Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}