{"record":{"id":"240a529b0b47b1ab","repo":"leptos-rs/leptos","slug":"could-not-deserialize-props","errorCode":null,"errorMessage":"could not deserialize props","messagePattern":"could not deserialize props","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"leptos_macro/src/component.rs","lineNumber":530,"sourceCode":"                quote! {{\n                    #destructure\n                    let mut props = #props_name::builder()\n                        #prop_builders\n                        #children\n                        .build();\n\n                    #optional_props\n\n                    props\n                }}\n            } else {\n                quote! {}\n            };\n            let deserialize_island_props = if is_island_with_other_props {\n                quote! {\n                    let props = el.dataset().get(::leptos::wasm_bindgen::intern(\"props\"))\n                        .and_then(|data| ::leptos::serde_json::from_str::<#props_serialized_name>(&data).ok())\n                        .expect(\"could not deserialize props\");\n                }\n            } else {\n                quote! {}\n            };\n\n            let hydrate_fn_name = hydrate_fn_name.as_ref().unwrap();\n\n            let hydrate_fn_inner = quote! {\n                #deserialize_island_props\n                let island = #name(#island_props);\n                let state = island.hydrate_from_position::<true>(&el, ::leptos::tachys::view::Position::Current);\n                // TODO better cleanup\n                std::mem::forget(state);\n            };\n            if *is_lazy {\n                let outer_name =\n                    Ident::new(&format!(\"{name}_loader\"), name.span());\n","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/leptos-rs/leptos/blob/32d20f6c9d517451d77beb68d88c7716823dac41/leptos_macro/src/component.rs#L512-L548","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before (server: old struct) / client expects new field\nstruct Props { a: u32 }          // server serialized only {\"a\":1}\nstruct Props { a: u32, b: String } // client deserialize fails -> panic\n// after\n// rebuild both server and client from the same commit so both use struct Props { a: u32, b: String }","handlingStrategy":"try-catch","validationCode":"// Client-side pre-check before hydration:\nlet ok = el\n    .dataset()\n    .get(wasm_bindgen::intern(\"props\"))\n    .map(|d| serde_json::from_str::<PropsSerialized>(&d).is_ok())\n    .unwrap_or(false);\nif !ok { /* re-render island client-side instead of hydrating */ }","typeGuard":"fn has_valid_props(el: &web_sys::Element) -> bool {\n    el.dataset()\n        .get(wasm_bindgen::intern(\"props\"))\n        .and_then(|d| serde_json::from_str::<PropsSerialized>(&d).ok())\n        .is_some()\n}","tryCatchPattern":"// Hydration itself panics via expect; wrap the hydrate call:\nlet result = std::panic::catch_unwind(|| hydrate_island(el));\nif result.is_err() {\n    // fall back to client-side (CSR) mount of the island\n}","preventionTips":["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"],"tags":["hydration","islands","serde","deserialization","panic"],"backgroundTag":"props-deserialization-failed","analyzedSha":"32d20f6c9d517451d77beb68d88c7716823dac41","analyzedAt":"2026-09-01T18:55:42.580Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}