leptos-rs/leptos · error
couldn't serialize island props
Error message
couldn't serialize island props
What it means
In the #[component] macro, when a component is an island that has props beyond those captured on the client (is_island_with_other_props), the macro generates code that serializes all props to JSON at runtime via serde_json::to_string(&props).expect("couldn't serialize island props"). This panics if any prop type is not JSON-serializable at runtime (e.g. contains non-serializable data like functions, channels, or unserializable custom types).
Source
Thrown at leptos_macro/src/component.rs:306
#[cfg(not(feature = "tracing"))]
{
(quote!(), quote!(), quote!(), quote!())
}
};
let component_id = name.to_string();
let hydrate_fn_name = is_island.then(|| {
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
island.hash(&mut hasher);
let caller = hasher.finish() as usize;
Ident::new(&format!("{component_id}_{caller:?}"), name.span())
});
let island_serialize_props = if is_island_with_other_props {
quote! {
let _leptos_ser_props = ::leptos::serde_json::to_string(&props).expect("couldn't serialize island props");
}
} else {
quote! {}
};
let island_serialized_props = if is_island_with_other_props {
quote! {
.with_props( _leptos_ser_props)
}
} else {
quote! {}
};
let body_name = unmodified_fn_name_from_fn_name(&body_name);
let body_expr = if is_island {
quote! {
::leptos::reactive::owner::Owner::new().with(|| {
::leptos::reactive::owner::Owner::with_hydration(move || {
::leptos::tachys::reactive_graph::OwnedView::new({View on GitHub (pinned to 32d20f6c9d)
Solutions
- Make every island prop implement Serialize (and Deserialize for hydration); add #[derive(Serialize, Deserialize)] to custom types
- Remove non-serializable props (callbacks, Rc/NodeRef) from islands or pass only primitive/serializable data
- Avoid non-string map keys in props (use HashMap<String, _> not HashMap<MyEnum, _> unless keys serialize as strings)
- Handle serialization explicitly instead of relying on the macro's expect: serialize manually and pass as a String prop
Example fix
// before
#[component]
fn MyIsland(#[prop(into)] data: MyData) -> impl IntoView { ... } // MyData: no Serialize
// after
#[derive(Clone, serde::Serialize, serde::Deserialize)]
struct MyData { id: u32, name: String }
#[component]
fn MyIsland(data: MyData) -> impl IntoView { ... } Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate island props serializability in a test:
let _ = serde_json::to_string(&props)
.unwrap_or_else(|e| panic!("island props not serializable: {e}")); Type guard
fn is_island_serializable<T: serde::Serialize>(props: &T) -> bool {
serde_json::to_string(props).is_ok()
} Try / catch
// The expect panics; serialize yourself before the macro path and handle the Result:
match serde_json::to_string(&props) {
Ok(json) => { /* pass json as a String prop */ }
Err(e) => log::error!("island props serialization failed: {e}"),
} Prevention
- Derive Serialize (+Deserialize) on every island prop type
- Never put callbacks, Rc, NodeRef, or channels in island props
- Use HashMap<String, T> (string keys) in props
- Add a unit test that serializes each island's props struct
When it happens
Trigger: Declaring an #[component(island = true)] whose props include a type that fails Serialize at runtime — serialize returns Err (map keys not strings, unsupported types, poisoned serializer) — then hitting the generated expect during the island render path.
Common situations: Island props containing Rc/RefCell/callbacks or types with #[serde(skip)]-incompatible shapes; closures or generic types without Serialize bound; serde version mismatch producing non-string map keys.
Related errors
- could not deserialize props
- List of slots must not be empty
- Executor::spawn called, but no global 'spawn' function is co
- Executor::spawn_local called, but no global 'spawn_local' fu
- At {caller}, tried to spawn a Future with Executor::spawn()
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/68caa6f6539706c1.
Report an issue: GitHub.