leptos-rs/leptos · error
could not deserialize props
Error message
could not deserialize props
What it means
For islands with extra props, the macro generates hydration code that reads the serialized props from the element's data-props dataset attribute and deserializes it with serde_json::from_str::<PropsSerialized>(...).ok(), then .expect("could not deserialize props"). This panics on the client during hydration when the dataset attribute is missing or its JSON does not match the expected serialized props struct.
Source
Thrown at leptos_macro/src/component.rs:530
quote! {{
#destructure
let mut props = #props_name::builder()
#prop_builders
#children
.build();
#optional_props
props
}}
} else {
quote! {}
};
let deserialize_island_props = if is_island_with_other_props {
quote! {
let props = el.dataset().get(::leptos::wasm_bindgen::intern("props"))
.and_then(|data| ::leptos::serde_json::from_str::<#props_serialized_name>(&data).ok())
.expect("could not deserialize props");
}
} else {
quote! {}
};
let hydrate_fn_name = hydrate_fn_name.as_ref().unwrap();
let hydrate_fn_inner = quote! {
#deserialize_island_props
let island = #name(#island_props);
let state = island.hydrate_from_position::<true>(&el, ::leptos::tachys::view::Position::Current);
// TODO better cleanup
std::mem::forget(state);
};
if *is_lazy {
let outer_name =
Ident::new(&format!("{name}_loader"), name.span());
View on GitHub (pinned to 32d20f6c9d)
Solutions
- Ensure server and client use the exact same build of the app/crate so the serialized props struct layout matches
- Verify the island element actually carries the data-props attribute in the served HTML
- Make prop types symmetric in Serialize/Deserialize (same fields, no skip asymmetry, string-serializable map keys)
- Upgrade or align leptos/leptos_macro versions between the SSR binary and the client WASM
- If hydration is optional, guard by re-creating the island client-side instead of panicking
Example fix
// before (server: old struct) / client expects new field
struct Props { a: u32 } // server serialized only {"a":1}
struct Props { a: u32, b: String } // client deserialize fails -> panic
// after
// rebuild both server and client from the same commit so both use struct Props { a: u32, b: String } Defensive patterns
Strategy: try-catch
Validate before calling
// Client-side pre-check before hydration:
let ok = el
.dataset()
.get(wasm_bindgen::intern("props"))
.map(|d| serde_json::from_str::<PropsSerialized>(&d).is_ok())
.unwrap_or(false);
if !ok { /* re-render island client-side instead of hydrating */ } Type guard
fn has_valid_props(el: &web_sys::Element) -> bool {
el.dataset()
.get(wasm_bindgen::intern("props"))
.and_then(|d| serde_json::from_str::<PropsSerialized>(&d).ok())
.is_some()
} Try / catch
// Hydration itself panics via expect; wrap the hydrate call:
let result = std::panic::catch_unwind(|| hydrate_island(el));
if result.is_err() {
// fall back to client-side (CSR) mount of the island
} Prevention
- Build server and client from the same commit so prop structs match
- Keep Serialize/Deserialize symmetric on prop types (no skip asymmetry)
- Verify data-props is present in served HTML when debugging
- Pin and align leptos versions in the workspace
When it happens
Trigger: Hydrating an island whose data-props attribute was not emitted server-side; the server and client define the island with different props (version skew); the JSON was truncated/mutated; or the props type's Deserialize does not match its Serialize output (e.g. untagged enums, skipped fields).
Common situations: Server and client built from different crate versions so the props struct shape changed; hydration of islands rendered by a different framework path; WASI/CSR builds where dataset API returns None; manually edited DOM before hydrate.
Related errors
- couldn't serialize island props
- could not read manifest file
- 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/240a529b0b47b1ab.
Report an issue: GitHub.