leptos-rs/leptos · error

rendering B to HTML without filling it

Error message

rendering B to HTML without filling it

What it means

EitherKeepAliveState keeps only the currently shown side filled: if showing_b is true, self.b holds Some(B) while self.a is None (and vice versa). Rendering to HTML when show_b is true requires the B view to have been stored; this panic means the state claims branch B is shown but the B slot was never filled. It guards against an internally inconsistent EitherKeepAliveState.

Source

Thrown at tachys/src/view/either.rs:596

                    None => None,
                }
            },
        )
        .await;
        EitherKeepAlive { a, b, show_b }
    }

    fn to_html_with_buf(
        self,
        buf: &mut String,
        position: &mut Position,
        escape: bool,
        mark_branches: bool,
        extra_attrs: Vec<AnyAttribute>,
    ) {
        if self.show_b {
            self.b
                .expect("rendering B to HTML without filling it")
                .to_html_with_buf(
                    buf,
                    position,
                    escape,
                    mark_branches,
                    extra_attrs,
                );
        } else {
            self.a
                .expect("rendering A to HTML without filling it")
                .to_html_with_buf(
                    buf,
                    position,
                    escape,
                    mark_branches,
                    extra_attrs,
                );
        }

View on GitHub (pinned to 32d20f6c9d)

Solutions

  1. Fill both sides appropriately via the normal update path (mount/rebuild) before rendering to HTML.
  2. Ensure EitherKeepAliveState is only created through its constructor with the active view passed in.
  3. If building state manually, set b = Some(view) whenever show_b = true.

Example fix

// before
let state = EitherKeepAliveState { showing_b: true, a: None, b: None };
state.to_html_with_buf(...); // panics
// after
let state = EitherKeepAliveState { showing_b: true, a: None, b: Some(view_b) };
state.to_html_with_buf(...);
Defensive patterns

Strategy: validation

Validate before calling

if state.showing_b && state.b.is_none() {
    panic!("state says B is shown but b is not filled");
}
state.to_html_with_buf(&mut buf, position, escape, mark_branches, extra_attrs);

Type guard

fn b_side_filled<A, B>(state: &EitherKeepAliveState<A, B>) -> bool {
    !state.showing_b || /* b accessor */ true // ensure b is Some when showing_b
}

Try / catch

std::panic::catch_unwind(|| state.to_html_with_buf(&mut buf, position, escape, mark_branches, extra_attrs))
    .inspect_err(|_| eprintln!("EitherKeepAliveState had unfilled B branch during SSR"));

Prevention

When it happens

Trigger: Calling to_html_with_buf on an EitherKeepAliveState whose show_b flag is true but whose b field is None — i.e. the state was constructed or mutated without filling the B view (e.g. hand-built state, or deserialized/partially initialized state used in server-side rendering).

Common situations: SSR/streaming rendering of a hand-constructed EitherKeepAliveState; framework code that sets the branch flag without re-rendering the branch; custom view code manipulating EitherKeepAliveState fields directly.

Related errors


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