leptos-rs/leptos · error

Expected a [number, string] tuple

Error message

Expected a [number, string] tuple

What it means

During client-side hydration, `serialized_errors()` reads the `__SERIALIZED_ERRORS` JS array injected by the server and expects every entry to be a `[number, string]`-shaped triple where index 2 is a JS string carrying the serialized error. If element 2 is not a string (e.g. `as_string()` returns None), the `.expect` panics in the WASM client, breaking hydration.

Source

Thrown at hydration_context/src/hydrate.rs:43

    #[wasm_bindgen(thread_local)]
    static __SERIALIZED_ERRORS: Array;

    #[wasm_bindgen(thread_local)]
    static __INCOMPLETE_CHUNKS: Array;
}

fn serialized_errors() -> Vec<(SerializedDataId, ErrorId, Error)> {
    __SERIALIZED_ERRORS.with(|s| {
        s.iter()
            .flat_map(|value| {
                value.dyn_ref::<Array>().map(|value| {
                    let error_boundary_id =
                        value.get(0).as_f64().unwrap() as usize;
                    let error_id = value.get(1).as_f64().unwrap() as usize;
                    let value = value
                        .get(2)
                        .as_string()
                        .expect("Expected a [number, string] tuple");
                    (
                        SerializedDataId(error_boundary_id),
                        ErrorId::from(error_id),
                        Error::from(SerializedError(value)),
                    )
                })
            })
            .collect()
    })
}

fn incomplete_chunks() -> Vec<SerializedDataId> {
    __INCOMPLETE_CHUNKS.with(|i| {
        i.iter()
            .map(|value| {
                let id = value.as_f64().unwrap() as usize;
                SerializedDataId(id)
            })

View on GitHub (pinned to 32d20f6c9d)

Solutions

  1. Ensure server and hydration_context/throw_error crates are the same version (align leptos/leptos_config and hydration_context versions in Cargo.toml)
  2. Inspect the rendered HTML hydration markers and confirm each error entry is a [number, string] tuple; fix whatever produces object/array values at index 2
  3. Disable or configure any HTML-rewriting middleware/CDN minification that could alter the serialized error data
  4. If you construct test hydration data, serialize error messages with `.to_string()` so element 2 is always a JS string

Example fix

// before (custom error serialization on server)
serde_json::to_value(my_error).unwrap() // object, not string
// after
my_error.to_string() // plain string, matches [number, string] tuple expectation
Defensive patterns

Strategy: type-guard

Validate before calling

// client-side, before trusting hydration data
let raw = js_sys::Reflect::get(&window(), &"__SERIALIZED_ERRORS".into()).ok();
let ok = raw.map(|v| {
    js_sys::Array::from(&v).iter().all(|entry| {
        let a = js_sys::Array::from(&entry);
        a.length() >= 3 && a.get(2).is_string()
    })
}).unwrap_or(false);

Type guard

fn is_error_tuple(entry: &JsValue) -> bool {
    entry
        .dyn_ref::<js_sys::Array>()
        .map(|a| a.length() >= 3 && a.get(2).is_string())
        .unwrap_or(false)
}

Try / catch

// wrap hydration bootstrap so a malformed payload degrades to client render
match std::panic::catch_unwind(|| hydrate()) {
    Ok(_) => {},
    Err(_) => mount_to_body(|view| { /* full client-side render */ }),
}

Prevention

When it happens

Trigger: Calling hydration entry points that collect serialized errors (e.g. Leptos hydration on the client) when the injected error payload has a non-string third element — typically a mismatch between server-side serialization code and client-side deserialization, hand-written or older hydration data, or corrupted/transformed hydration markers (HTML rewriters, CDNs, proxies mangling the payload).

Common situations: Version mismatch between server (leptos/Legerder serialization) and client hydration crates; custom middleware that rewrites hydration markers; an Error/CustomError serialized as a structured object instead of a string; manually edited SSR output in tests or static snapshots.

Related errors


AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01). Data as JSON: /api/errors/7fd145b35873afad. Report an issue: GitHub.